單標簽實現複雜的棋盤佈局

来源:https://www.cnblogs.com/coco1s/archive/2022/09/20/16710203.html
-Advertisement-
Play Games

最近,有群友問我,他們的一個作業,儘量使用少的標簽去實現這樣一個象棋佈局: 他用了 60 多個標簽,而他的同學,只用了 6 個,問我有沒有辦法儘可能的做到利用更少的標簽去完成這個佈局效果。 其實,對於一個頁面的佈局而言,標簽越少不一定是好事,我們在考慮 DOM 的消耗的同時,也需要關註代碼的可讀性, ...


最近,有群友問我,他們的一個作業,儘量使用少的標簽去實現這樣一個象棋佈局:

用了 60 多個標簽,而他的同學,只用了 6 個,問我有沒有辦法儘可能的做到利用更少的標簽去完成這個佈局效果。

其實,對於一個頁面的佈局而言,標簽越少不一定是好事,我們在考慮 DOM 的消耗的同時,也需要關註代碼的可讀性,以及後續基於這個佈局的製作的交互的難易性等等。

當然,僅僅從用更少的標簽完成這個佈局的角度而言,我們能夠把標簽數壓縮到多少呢個?(不考慮 <body><html>

答案是 1 個

本文就嘗試使用一個標簽完成這個效果,當然,這僅僅是探索 CSS 的極限,不代表我推薦在實際業務中這樣去寫。

我們對整個佈局進行一下拆分,大致可以分為三部分:網格 + 虛線交叉十字 + 特殊符號:

並且,像虛線交叉十字和特殊的符號都不止一個,這裡必然會有一些技巧存在。

使用漸變實現網格

OK,首先,我們實現最簡單的網格佈局:

不考慮最外層的一圈邊框,我們可以首先利用多重線性漸變實現一個網格佈局:

<div class="g-grid"></div>
.g-grid {
    width: 401px;
    height: 451px;
    background:
        repeating-linear-gradient(#000, #000 1px, transparent 1px, transparent 50px),
        repeating-linear-gradient(90deg, #000, #000 1px, transparent 1px, transparent 50px);
    background-repeat: no-repeat;
    background-size: 100% 100%, 100% 100%;
    background-position: 0 0, 0 0;
}

效果如下:

在最外層加一層邊框有非常多辦法,這裡我們簡單使用 outline 配合 outline-offset 即可:

.g-grid {
    width: 401px;
    height: 451px;
    background:
        repeating-linear-gradient(#000, #000 1px, transparent 1px, transparent 50px),
        repeating-linear-gradient(90deg, #000, #000 1px, transparent 1px, transparent 50px);
    background-repeat: no-repeat;
    background-size: 100% 100%, 100% 100%;
    background-position: 0 0, 0 0;
    outline: 1px solid #000;
    outline-offset: 5px;
}

這樣,一個架子就差不多了:

當然,棋盤中間的一行,是沒有格子的。要將上述漸變代碼處理一下,可以分成上下兩塊,利用 background-sizebackground-position 進行分隔。

當然,我們也可以在最上層直接再疊一層純白色漸變:

.grid {
    // ...
    background:
        // 最上層疊加一層白色漸變
        linear-gradient(#fff, #fff),
        // 下麵兩個重覆線性漸變實現網格
        repeating-linear-gradient(#000, #000 1px, transparent 1px, transparent 50px),
        repeating-linear-gradient(90deg, #000, #000 1px, transparent 1px, transparent 50px);
    background-repeat: no-repeat;
    background-size: calc(100% - 2px) 49px, 100% 100%, 100% 100%;
    background-position: 1px 201px, 0 0, 0 0;
}

到這裡,其實核心還都是漸變,目前共 3 層漸變,得到這樣一個效果:

利用漸變實現交叉虛線十字

OK,我們繼續,我們需要基於上述的基礎,得到兩個交叉虛線十字,像是這樣:

這裡其實真的有難度。想象一下,如果給你一個 DIV,去實現其中一個,可以怎麼做呢?

通過 border 中特有的虛線 dashed?這樣可能就需要兩個元素設置單邊的虛線邊框,然後旋轉相交得到。(可以利用元素的兩個偽元素,實現在一個 DOM 中)。

當然,這樣的話,我們的標簽就不夠用了。

所以,這裡我們另闢蹊徑,繼續使用漸變

首先,打個樣,如果是一個 100px x 100px 的 DIV,可以怎麼利用漸變去畫交叉虛線十字呢?

<div></div>
div {
    position: relative;
    margin: auto;
    width: 100px;
    height: 100px;
    border: 1px solid #000;
    background: linear-gradient(
        45deg,
        transparent 0, transparent calc(50% - 0.5px),
        #000 calc(50% - 0.5px), #000 calc(50% + 0.5px),
        transparent calc(50% + 0.5px), transparent 0);
}

我們首先利用漸變,實現一條 1px 的斜線,註意這裡的漸變是從透明到黑色到透明,實現了一條 45° 的斜線。

我們再反 45° 過來,利用多重線性漸變,實現透明到白色的漸變效果:

div {
    position: relative;
    margin: auto;
    width: 100px;
    height: 100px;
    border: 1px solid #000;
    background: 
        // 漸變 1 
        repeating-linear-gradient(-45deg, transparent 0, transparent 5px, #fff 5px, #fff 10px),
        // 漸變 2
        linear-gradient(45deg,
        transparent 0, transparent calc(50% - 0.5px),
        #000 calc(50% - 0.5px), #000 calc(50% + 0.5px),
        transparent calc(50% + 0.5px), transparent 0);
}

這樣,我們就得到了一條虛線:

好吧,這一步有一些同學可能會有一點疑惑,怎麼變過來的。

我把上面漸變 1的透明色改成黑色,就很好理解了:

想象一下,上圖的黑色部分,如果是透明的,就能透出原本的那條斜線沒有被白色遮擋住的地方。

這裡,需要提一下,在漸變中,越是先書寫的漸變,層級越高。

好,有了上面的鋪墊,我們基於上面的代碼,再繼續利用漸變,把上下兩個交叉虛線十字補齊即可:

.g-grid {
    width: 401px;
    height: 451px;
    outline: 1px solid #000;
    outline-offset: 5px;
    background:
        // 最上層的白色塊,擋住中間的網格
        linear-gradient(#fff, #fff),
        // 實現網格佈局
        repeating-linear-gradient(#000, #000 1px, transparent 1px, transparent 50px),
        repeating-linear-gradient(90deg, #000, #000 1px, transparent 1px, transparent 50px),
        // 棋盤上方的虛線1
        repeating-linear-gradient(-45deg, transparent 0, transparent 5px, #fff 5px, #fff 10px),
        linear-gradient(45deg, transparent, 
            transparent calc(50% - 0.5px), 
            #000 calc(50% - 0.5px), 
            #000 calc(50% + 0.5px), 
            transparent calc(50% + 0.5px), 
            transparent 0),
        // 棋盤上方的虛線2
        repeating-linear-gradient(45deg, transparent 0, transparent 5px, #fff 5px, #fff 10px),
        linear-gradient(-45deg, transparent, 
            transparent calc(50% - 0.5px), 
            #000 calc(50% - 0.5px), 
            #000 calc(50% + 0.5px), 
            transparent calc(50% + 0.5px), 
            transparent 0),
        // 棋盤下方的虛線1
        repeating-linear-gradient(-45deg, transparent 0, transparent 5px, #fff 5px, #fff 10px),
        linear-gradient(45deg, transparent, 
            transparent calc(50% - 0.5px), 
            #000 calc(50% - 0.5px), 
            #000 calc(50% + 0.5px), 
            transparent calc(50% + 0.5px), 
            transparent 0),
        // 棋盤下方的虛線2
        repeating-linear-gradient(45deg, transparent 0, transparent 5px, #fff 5px, #fff 10px),
        linear-gradient(-45deg, transparent, 
            transparent calc(50% - 0.5px), 
            #000 calc(50% - 0.5px), 
            #000 calc(50% + 0.5px), 
            transparent calc(50% + 0.5px), 
            transparent 0);
    background-repeat: no-repeat;
    background-size: 
        calc(100% - 2px) 49px, 100% 100%, 100% 100%, 
        // 交叉虛線 1
        100px 100px, 100px 100px, 100px 100px, 100px 100px,
        // 交叉虛線 2
        100px 100px, 100px 100px, 100px 100px, 100px 100px;
    background-position: 
        1px 201px, 0 0, 0 0, 
        // 交叉虛線 1
        151px 0, 151px 0, 151px 0, 151px 0,
        // 交叉虛線 2
        151px 350px, 151px 350px, 151px 350px, 151px 350px;
}

嚯,這漸變代碼確實複雜了點,但是其實每一塊的作用都是很清晰的,這樣,我們的棋盤就變成了這樣:

藉助偽元素及 box-shadow 實現剩餘符合

到這裡,我們僅僅使用了元素本身,要知道,我們還有元素的兩個偽元素沒使用。要實現的只剩下多個的這個符合:

因為一共要實現 12 個這樣的符號,有的符合還是不完整的,所有這些要在剩餘的元素的兩個偽元素中完成。可選的方法思來想去,也只有 box-shadow 了。

利用 box-shadow 能夠非常好的複製自身。這個技巧其實也反覆講過非常多次了。

我們首先利用元素的一個偽元素,在這個位置,實現一個短橫線:

代碼大致如下:

.g-grid {
    // ...
    &::before {
        content: "";
        position: absolute;
        top: 95px;
        left: 35px;
        width: 10px;
        height: 1px;
        background: #000;
    }
}

我們利用 box-shadow 複製自身,可以完成一半橫線效果。當然這裡由於是個鏡面佈局,可以利用鏡像 -webkit-box-reflect: below 減少一半的代碼:

.g-grid {
    // ...
    &::before {
        content: "";
        position: absolute;
        top: 95px;
        left: 35px;
        width: 10px;
        height: 1px;
        background: #000;
        box-shadow: 
            20px 0, 0 10px, 20px 10px,
            300px 0, 320px 0, 300px 10px, 320px 10px,
            -30px 50px, -30px 60px,
            50px 50px, 50px 60px, 70px 50px, 70px 60px,
            150px 50px, 150px 60px, 170px 50px, 170px 60px,
            250px 50px, 250px 60px, 270px 50px, 270px 60px,
            350px 50px, 350px 60px;
        -webkit-box-reflect: below 259px;
    }
}

效果如下:

最後,利用另外一個偽元素,完成另外一半的豎向橫線即可:

.g-grid {
    // ...
    &::before {
        // ...
    }
    &::after {
        // ...
        box-shadow: 
            10px 0, 0 20px, 10px 20px,
            300px 0px, 300px 20px, 310px 0, 310px 20px,
            -40px 50px, -40px 70px,
            50px 50px, 50px 70px, 60px 50px, 60px 70px,
            150px 50px, 150px 70px, 160px 50px, 160px 70px,
            250px 50px, 250px 70px, 260px 50px, 260px 70px,
            350px 50px, 350px 70px;
        -webkit-box-reflect: below 260px;
    }
}

這樣,我們就在一個標簽內,得到這樣一個效果:

當然,還剩下楚河、漢界 4 個字,這個也簡單直接加在 div 中即可,配合一些簡單的 CSS 調整,整個效果就在一個標簽內完成啦:

完整的代碼你可以戳這裡:CodePen Demo -- CSS Chess board

好,實際中我確實不太推薦這麼去寫,純粹是為了實現而實現,少了很多代碼可讀性的考量。因此,本文更多的是給大家帶來一些思路,當遇到類似的問題的使用能夠有更多的靈感。

最後

好了,本文到此結束,希望本文對你有所幫助

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.起步 1.1 配置uni-app開發環境 什麼是uni-app,就是基於vue的一個開發框架,可以將我們寫的一套代碼,同時發佈到ios、安卓、小程式等多個平臺 ==官方推薦使用Hbuilderx來寫uni-app項目== 下載之後可以將預設改為vscode 進入hbuilder插件市場下載scs ...
  • 前端技術的發展不斷融入了很多後端的思想,逐步形成前端的 ”四個現代化“:工程化、模塊化、規範化、流程化。這個主題介紹 *模塊化* ,主要內容包括模塊化前傳(早期模塊化的實現)、模塊化的四個規範(Common JS、AMD、CMD、ESM)。本文就聊聊早期的模塊化。 ...
  • 現在的很多程式應用,基本上都是需要多端覆蓋,因此基於一個Web API的後端介面,來構建多端應用,如微信、H5、APP、WInForm、BS的Web管理端等都是常見的應用。本篇隨筆繼續分析總結一下項目開發的經驗,針對頁面組件化開發經驗方面進行一些梳理總結,內容包括組件的概念介紹,簡單頁面組件的抽取開... ...
  • 每日3題 1 以下代碼執行後,控制臺中的輸出內容為? // index.js console.log(1); import { sum } from "./sum.js"; console.log(sum(1, 2)); //sum.js console.log(2); export const s ...
  • 導讀:面對多種多樣的跨端訴求,有哪些跨端方案?跨端的本質是什麼?作為業務技術開發者,應該怎麼做?本文分享阿裡巴巴ICBU技術部在跨端開發上的一些思考,介紹了當前主流的跨端方案,以及跨端開發的經驗心得。 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 最近在研究一個基於TP6的框架CRMEB,這裡分享下我的開發心得 首先在上篇文章中,我們安裝了CRMEBphp介面項目,需要可以看這一篇 TP6框架--CRMEB學習筆記:項目初始化+環境配置 1.獲取項目 這裡是git地址 https: ...
  • 通過 antd 框架的 Upload 控制項,採用手動上傳的方式,先選擇需要上傳的文件(控制文件數量以及大小),再根據所選的文件列表,迴圈上傳,期間通過 Spin 控制項提示上傳中。 ...
  • 隨著前端的範疇逐漸擴大,深度逐漸下沉,富前端必然帶來的一個問題就是性能。特別是在大型複雜項目中,重前端業務可能因為一個小小的數據依賴,導致整個頁面卡頓甚至崩潰。本文基於Quick BI(數據可視化分析平臺)歷年架構變遷中性能的排查、解決和總結出的“個性”問題,嘗試總結整個前端層面相對“共性”的問題,... ...
一周排行
    -Advertisement-
    Play Games
  • 1. 說明 /* Performs operations on System.String instances that contain file or directory path information. These operations are performed in a cross-pla ...
  • 視頻地址:【WebApi+Vue3從0到1搭建《許可權管理系統》系列視頻:搭建JWT系統鑒權-嗶哩嗶哩】 https://b23.tv/R6cOcDO qq群:801913255 一、在appsettings.json中設置鑒權屬性 /*jwt鑒權*/ "JwtSetting": { "Issuer" ...
  • 引言 集成測試可在包含應用支持基礎結構(如資料庫、文件系統和網路)的級別上確保應用組件功能正常。 ASP.NET Core 通過將單元測試框架與測試 Web 主機和記憶體中測試伺服器結合使用來支持集成測試。 簡介 集成測試與單元測試相比,能夠在更廣泛的級別上評估應用的組件,確認多個組件一起工作以生成預 ...
  • 在.NET Emit編程中,我們探討了運算操作指令的重要性和應用。這些指令包括各種數學運算、位操作和比較操作,能夠在動態生成的代碼中實現對數據的處理和操作。通過這些指令,開發人員可以靈活地進行算術運算、邏輯運算和比較操作,從而實現各種複雜的演算法和邏輯......本篇之後,將進入第七部分:實戰項目 ...
  • 前言 多表頭表格是一個常見的業務需求,然而WPF中卻沒有預設實現這個功能,得益於WPF強大的控制項模板設計,我們可以通過修改控制項模板的方式自己實現它。 一、需求分析 下圖為一個典型的統計表格,統計1-12月的數據。 此時我們有一個需求,需要將月份按季度劃分,以便能夠直觀地看到季度統計數據,以下為該需求 ...
  • 如何將 ASP.NET Core MVC 項目的視圖分離到另一個項目 在當下這個年代 SPA 已是主流,人們早已忘記了 MVC 以及 Razor 的故事。但是在某些場景下 SSR 還是有意想不到效果。比如某些靜態頁面,比如追求首屏載入速度的時候。最近在項目中回歸傳統效果還是不錯。 有的時候我們希望將 ...
  • System.AggregateException: 發生一個或多個錯誤。 > Microsoft.WebTools.Shared.Exceptions.WebToolsException: 生成失敗。檢查輸出視窗瞭解更多詳細信息。 內部異常堆棧跟蹤的結尾 > (內部異常 #0) Microsoft ...
  • 引言 在上一章節我們實戰了在Asp.Net Core中的項目實戰,這一章節講解一下如何測試Asp.Net Core的中間件。 TestServer 還記得我們在集成測試中提供的TestServer嗎? TestServer 是由 Microsoft.AspNetCore.TestHost 包提供的。 ...
  • 在發現結果為真的WHEN子句時,CASE表達式的真假值判斷會終止,剩餘的WHEN子句會被忽略: CASE WHEN col_1 IN ('a', 'b') THEN '第一' WHEN col_1 IN ('a') THEN '第二' ELSE '其他' END 註意: 統一各分支返回的數據類型. ...
  • 在C#編程世界中,語法的精妙之處往往體現在那些看似微小卻極具影響力的符號與結構之中。其中,“_ =” 這一組合突然出現還真不知道什麼意思。本文將深入剖析“_ =” 的含義、工作原理及其在實際編程中的廣泛應用,揭示其作為C#語法奇兵的重要角色。 一、下劃線 _:神秘的棄元符號 下劃線 _ 在C#中並非 ...