整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          大膽嘗試這些新的CSS屬性,釋放CSS的力量吧(一)

          大膽嘗試這些新的CSS屬性,釋放CSS的力量吧(一)

          載說明:原創不易,未經授權,謝絕任何形式的轉載

          本文章系《Unleashing the Power of CSS》(釋放CSS的力量,暫且這么翻譯吧)一書的學習筆記,希望通本書的學習,系統的梳理下CSS相關的高級新特性。本篇文章是其第一部分,由于全書英文版,理解和閱讀會有偏差,歡迎各位大佬們指正,我們一起共同提高。

          開篇

          在過去的幾年里,CSS引入了許多新的改進功能,并且跨瀏覽器的努力提高了兼容性,使這門語言比以往任何時候都更加穩定!讓我們回顧一下布局、響應式設計、元素樣式、屬性和選擇器方面的這些增強功能,并且也來看一看即將推出的新功能。

          現在,瀏覽器之間新功能的協調實施意味著我們幾乎可以在它們出現的同時開始使用這些功能,這對于保持我們的樣式表盡可能簡單非常有幫助。現在,只需幾個單行屬性就可以替代多行的hacky解決方案。在某些情況下,新提供的功能甚至可能意味著我們可以刪除以前需要的JavaScript解決方案,以解決舊限制!

          新的和增強的屬性

          Custom Properties(自定義屬性或變量)

          隨著Internet Explorer 11的生命周期進入尾聲,現在是時候開始使用自定義屬性了!自定義屬性,也被稱為“CSS變量”,允許我們定義可在樣式表中重復使用的值。自定義屬性可以作為屬性的整個值或部分值使用,我們還可以在JavaScript中修改自定義屬性。

          aspect-ratio

          一種新的屬性可以消除“填充hack”,它是 aspect-ratio 。它按照其名稱的意思,允許我們為元素定義一個縱橫比。我所提到的 hack 通常用于保持視頻嵌入的16:9比例。現在,通過這個屬性和聲明 aspect-ratio: 16/9 ,可以實現這個比例。它還是實現完美正方形的快速方法,使用 aspect-ratio: 1 即可。

          這是一個代碼演示,展示了如何使用 aspect-ratio 與舊屬性 object-fit 結合使用,以保持一致的頭像大小,無論原始圖像的比例如何,而且不會扭曲圖像。

          Html部分

          <ul class="avatar-list">
            <li>
              <figure>
                <img src='https://images.unsplash.com/photo-1640952131659-49a06dd90ad2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NjkwNTE0MTQ&ixlib=rb-4.0.3&q=80&w=400' alt=''>
                <figcaption>Aaron Fizzle</figcaption>
              </figure>
            </li>
            <li>
              <figure>
                <img src='https://images.unsplash.com/photo-1544725176-7c40e5a71c5e?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NjkwNTE0MTQ&ixlib=rb-4.0.3&q=80&w=400' alt=''>
                <figcaption>Lily Sebastian</figcaption>
              </figure>
            </li>
            <li>
              <figure>
                <img src='https://images.unsplash.com/photo-1628157588553-5eeea00af15c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NjkwNTE1MTU&ixlib=rb-4.0.3&q=80&w=400' alt=''>
                <figcaption>Devon Albian</figcaption>
              </figure>
            </li>
          </ul>

          Css部分

          .avatar-list img {
            /* Make it a square */
            aspect-ratio: 1;
            /* Fit the image to it's container without distortion */
            object-fit: cover;
            /* Make the square round */
            border-radius: 50%;
            width: 100%; /* Make sure the image fills the container */
            height: 100%; /* Make sure the image fills the container */
          }
          
          * {
            box-sizing: border-box;
            margin: 0;
          }
          
          html {
            height: 100%;
          }
          
          body {
            min-height: 100%;
            font-family: system-ui, sans-serif;
            display: grid;
            place-content: center;
            background-color: mediumvioletred;
            padding-inline: 1rem;
          }
          
          /* Standard responsive image fix */
          img {
            max-width: 100%;
          }
          
          .avatar-list {
            list-style: none;
            padding: 0;
            background: #fff;
            border-radius: 0.5rem;
            box-shadow: 0.25rem 0.25rem 0.5rem -0.15rem hsl(0 0% 0% / 30%);
            border: 1px solid hsl(0 0% 0% / 10%);
          }
          
          .avatar-list li {
            position: relative;
            padding: 3%;
            font-size: 1.35rem;
            font-size: clamp(0.8rem, 0.8rem + 2cqi, 1.5rem);
            color: hsl(0 0% 45%);
            letter-spacing: 0.03em;
          }
          
          .avatar-list li + li::before {
            content: "";
            position: absolute;
            top: 0;
            left: calc(15% + 1rem);
            right: 3%;
            border-top: 1px solid hsl(0 0% 0% / 15%);
          }
          
          .avatar-list figure {
            display: grid;
            grid-template-columns: 15% 1fr;
            align-items: center;
            gap: 1rem;
          }
          

          https://codepen.io/SitePoint/pen/oNaNaao

          Individual Transform Properties(個體變換屬性)

          瀏覽器中還新增了各自的變換屬性。Chrome 104進行的CSS變換具有獨立的屬性。這些屬性是 scale , rotate 和 translate ,您可以使用它們來單獨定義變換的各個部分。

          并非所有的轉換函數都有相應的個體屬性,例如 skewX() 和 matrix() 。

          .target {
            translate: 50% 0;
            rotate: 30deg;
            scale: 1.2;
          }

          Logical Properties(邏輯屬性)

          CSS的Logical Properties(邏輯屬性)是一種用于處理文本和布局的屬性,它們考慮了文本流的邏輯方向而不是物理方向。在CSS中,文檔可以采用不同的書寫模式,例如從左到右(LTR)的水平書寫模式和從右到左(RTL)的水平書寫模式,以及垂直書寫模式。Logical Properties的目標是使樣式更加靈活,適應不同的書寫模式,而不需要為每種書寫模式都編寫不同的樣式。

          如果我們要為國際受眾管理內容,則可以考慮使用邏輯屬性。適用于大多數 CSS 2.1 屬性,邏輯變體考慮了文本的編寫模式和流。對于標準的英文文本,我們將“左/右”換成“內聯”,用“top/bottom”換成“block”:

          .element {
            margin-block: 2rem;
          }

          如上例所示,邏輯屬性還提供了一次設置兩邊的簡寫,其中 margin-block 水平寫入模式等效于 set margin-top 和 margin-bottom 。

          新的選擇器

          近期對CSS最有影響力的三個變化是:is、:where和:has偽類選擇器。以下是它們的概述:

          :is() ,它用于選擇滿足括號內任何選擇器的元素。這個偽類可以幫助你編寫更簡潔和可維護的 CSS 代碼,尤其是當你需要同時匹配多個選擇器時。例如, :is(#id, a, .class) 將具有一個 id 的特異性。

          :where 是一個 CSS 偽類選擇器,它與 :is 偽類選擇器類似,可以用于選擇滿足括號內任何選擇器的元素。它的語法也與 :is 相似,但有一個重要的區別::where 不會影響優先級。

          與 :is 不同,:where 不會增加或改變樣式規則的優先級。這意味著,無論你在樣式表中的什么位置使用 :where,它都不會改變選擇器的權重,不會增加特異性(specificity),也不會影響其他樣式規則的優先級。

          這使得 :where 在一些情況下非常有用,特別是當你需要選擇一組元素,但不希望影響其他選擇器的優先級時。例如,假設你有一個已經存在的 CSS 樣式表,其中包含了一些具有不同權重和特異性的樣式規則,但你希望添加一個新的規則,同時不改變其他規則的優先級,你可以使用 :where 來實現這一點。

          /* 不使用 :where */
          .btn {
            background-color: #3498db;
          }
          
          /* 使用 :where,不影響其他規則的優先級 */
          :where(.btn-primary, .btn-secondary, .btn-danger) {
            background-color: #3498db;
            color: white;
          }

          :has() 是期待已久的“父選擇器”,它允許檢查父元素是否包含特定的子元素,并對父元素進行樣式設置,或者擴展為復合選擇器以對子元素進行樣式設置。(本系列教程中有關于 :has() 的完整教程。)

          這個演示利用 :where() 、 :is() 和 :has() 來創建一個作者簡介組件,根據是否有頭像來改變網格顯示屬性。

          <aside class="bio">
            <img class="avatar" src='https://images.unsplash.com/photo-1554727242-741c14fa561c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NzExNDcxMjM&ixlib=rb-4.0.3&q=80&w=400' alt=''>
            <h2>Jane Stylesheet</h2>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsa quam aspernatur, nobis ex rem iure!</p>
          </aside>
          
          <aside class="bio">
            <h2>Bob Markup</h2>
            <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Aliquam neque a blanditiis praesentium impedit.</p>
          </aside>
          * {
            box-sizing: border-box;
            margin: 0;
          }
          
          body {
            font-family: system-ui;
            padding: 3vw;
            background-color: mediumvioletred;
          }
          
          img {
            display: block;
            max-width: 100%;
          }
          
          :where(* + *) {
            margin-block-start: 1rem;
          }
          
          .bio :is(h2, p) {
            margin-block-start: 0;
          }
          
          .bio {
            background-color: white;
            display: grid;
            gap: 1rem;
            border-radius: 0.5rem;
            padding: 5%;
            box-shadow: 0 0 10px -2px hsl(0 0% 0% / 85%);
          }
          
          .bio:has(.avatar) {
            grid-template-areas: "avatar name" "avatar bio";
            grid-template-columns: min(25vw, 80px) 1fr;
          }
          
          .bio:has(.avatar) :not(.avatar) {
            grid-column: bio;
          }
          
          .bio .avatar {
            grid-area: avatar;
          }
          
          .avatar {
            aspect-ratio: 1;
            object-fit: cover;
            border-radius: 50%;
          }

          https://codepen.io/SitePoint/pen/WNaeJOy

          :has() 在撰寫本文時僅部分瀏覽器支持,因此上述演示目前僅適用于Safari 15.4+和Chrome/Edge 105+,以及啟用 layout.css.has-selector.enabled 標志的Firefox 103。

          增強的 :not()

          最近,:not() 選擇器已經增強,可以接受一個選擇器列表,這使得 :not(nav a, footer a) 成為有效的語法。然而,與 :is() 和 :where() 不同,這個更新并沒有使 :not() 對于無效的選擇器更加寬容,因為需要保持向后兼容性支持。

          焦點選擇器

          下面的兩個新偽類都會影響焦點行為。當子元素處于焦點狀態時,可以使用 :focus-within 選擇器來為父元素設置樣式,比如表單字段周圍的容器。對于元素焦點樣式,我們現在可以使用 :focus-visible ,它最近取代了 :focus 成為跨瀏覽器默認的元素焦點樣式。

          下面是 :focus-within 的一些關鍵點和與 :focus 的區別:

          :focus-within 選擇器:

          • 選擇包含有焦點元素的祖先元素。
          • 當用戶在頁面上的某個元素上聚焦(例如,輸入框或按鈕),并且該元素是其祖先元素(例如,一個表單或一個包含該輸入框的 div)內的子元素時,祖先元素將匹配 :focus-within。
          • 通常用于創建包含輸入框的表單的外觀,以在用戶輸入時改變整個表單的樣式或行為。

          :focus 選擇器:

          • 選擇當前具有焦點的元素。
          • 通常用于樣式化或增強當前擁有焦點的元素,例如,更改輸入框的邊框顏色或文本區域的背景顏色。
          • 不會選擇包含有焦點元素的父元素。

          假設有以下 HTML 結構:

          <div class="container">
            <input type="text" id="username" />
            <input type="password" id="password" />
          </div>

          現在,我們可以使用 :focus 和 :focus-within 來添加一些樣式:

          /* 當輸入框具有焦點時,樣式化輸入框本身 */
          input:focus {
            border: 2px solid blue;
          }
          
          /* 當包含有焦點輸入框的容器具有焦點時,樣式化整個容器 */
          .container:focus-within {
            background-color: lightgray;
          }
          

          在上面的示例中,當用戶點擊輸入框時,輸入框自身會具有藍色邊框(使用 :focus 選擇器),同時包含有焦點輸入框的容器 .container 也會變為灰色背景(使用 :focus-within 選擇器)。這使得用戶在與表單交互時,不僅輸入框本身被強調,整個表單容器也能夠獲得焦點的可視反饋。

          總之,:focus-within 選擇器用于選擇包含有焦點元素的祖先元素,而 :focus 選擇器用于樣式化具有焦點的元素本身。這兩個選擇器可以一起使用,以創建更豐富的交互體驗。

          ::marker

          最后但并非最不重要的是,偽元素 ::marker 允許我們直接選擇和樣式化 <ul> 和 <ol> 元素上的列表項符號和編號,以及 <summary> 元素的“插入符號”。這意味著我們可以使用 ::marker 來僅改變列表的符號顏色!

          元素樣式的改進

          accent-color

          框架和設計系統最常見的改變之一是本地表單字段樣式。在 accent-color 屬性出現之前,甚至改變表單元素的顏色都是不可能的。現在,我們可以通過 accent-color 影響單選按鈕和復選框的選中外觀,以及范圍輸入和進度元素的填充狀態。

          下面是一個示例,演示了如何使用 accent-color 屬性:

          a {
            accent-color: blue;
          }
          

          在這個示例中,accent-color 屬性應用于所有鏈接元素 (<a>),并將鏈接的強調顏色設置為藍色。

          color-scheme

          如果我們想要根據用戶的淺色或深色模式偏好來調整我們的界面,可以使用自定義切換和/或 prefers-color-scheme 查詢,我們還應該添加color-scheme屬性。這提供了一種選擇,可以適應瀏覽器的UI元素,如滾動條、表單控件和CSS系統顏色。而 accent-color 讓我們可以為一些元素選擇自定義顏色, color-scheme 則要求瀏覽器進行更多的適應,例如要求文本輸入和文本區域以淺色或深色主題顯示。

          建議將此應用于 :root 元素,并按照網站默認值的順序列出這些值。換句話說,如果我們默認為淺色但支持深色,則列出 light dark 。如果我們默認為深色但支持淺色,則列出 dark light 。如果我們只支持 light 或 dark ,只需列出單個值即可:

          :root {
            color-scheme: light dark;
          }

          例如,你可以這樣定義一個明亮模式和一個暗模式的顏色方案:

          /* 明亮模式 */
          @media (prefers-color-scheme: light) {
            body {
              background-color: white;
              color: black;
            }
          }
          
          /* 暗模式 */
          @media (prefers-color-scheme: dark) {
            body {
              background-color: black;
              color: white;
            }
          }
          

          Forced-color Modes (強制色彩模式)

          為了完善關于顏色的主題,還有一個偏好查詢和屬性對需要討論。在Windows上,一些用戶需要“高對比度”主題,其中操作系統強制使用減少的調色板來代替我們定義的顏色。調色板填充系統顏色的值,替換背景、文本、按鈕和鏈接顏色等內容,而像盒子陰影這樣的樣式則被刪除。

          如果我們有使用顏色的關鍵樣式,比如產品顏色樣本,我們可能需要在 forced-colors 屬性旁邊使用 force-color-adjust 查詢。根據以下配對,我們原始的 .swatch 顏色將被保留:

          @media (forced-colors: active) {
            .swatch {
              forced-color-adjust: none;
            }
          }

          強制使用顏色應該謹慎使用,只有在用戶體驗受到高對比度主題顏色交換的負面影響時才使用。如果您對高對比度主題不熟悉,請了解如何使用強制顏色進行樣式設置。

          Text Decoration

          在文本裝飾方面,我們現在有可用的 text-underline-offset 屬性,它允許我們調整定義的 text-decoration 的位置,使其偏離原始位置。 text-decoration-thickness 伴隨屬性允許我們控制 text-decoration 的描邊粗細。結合使用這些屬性,可以消除使用邊框甚至偽元素來樣式化鏈接下劃線的hack。

          以下樣式規則將文本下劃線向下偏移 2 像素:

          a {
            text-decoration: underline;
            text-underline-offset: 2px;
          }
          

          結束

          由于文章內容篇幅有限,今天的內容就分享到這里,文章結尾,我想提醒您,文章的創作不易,如果您喜歡我的分享,請別忘了點贊和轉發,讓更多有需要的人看到。同時,如果您想獲取更多前端技術的知識,歡迎關注我,您的支持將是我分享最大的動力。我會持續輸出更多內容,敬請期待。

          載說明:原創不易,未經授權,謝絕任何形式的轉載

          在我的好奇心驅使下,我想為什么不去查看一些熱門網站,并了解一下它們是如何實現評論組件的布局。起初,我認為這將是一個簡單的任務,但實際并非如此。

          我花了很多時間試圖理解這是如何工作的,以及如何通過現代 CSS(如 :has、size container queries 和 style queries)來改進它。在本文中,我將引導您了解我的思考過程,并分享我在其中所得到的發現。

          簡介

          以下是我們將要構建的布局。乍一看,它可能看起來很簡單,但其中有很多微小的細節。

          我們有一個評論,可以嵌套兩個更深層次。我在本文中將這些稱為“深度”。

          圖中展示了深度是如何根據每個評論的嵌套級別而變化的。

          思考布局

          在深入細節之前,我更愿意先著手處理布局,并確保它能很好地運作。這樣的做法旨在探索現代CSS解決該問題的潛力。

          首先要記住的是HTML標記。評論的結構很適合使用無序列表<ul>。

          <ul>
            <li>
              <Comment />
            </li>
            <li>
              <Comment />
            </li>
          </ul>

          < Comment /> 充當評論組件的占位符。這是兩條評論的列表的HTML,沒有任何回復。

          如果對其中一條評論進行回復,那么將會添加一個新的 <ul>。

          <ul>
            <li>
              <!-- Main comment -->
              <Comment />
              <ul>
                <!-- Comment reply -->
                <li>
                  <Comment />
                </li>
              </ul>
            </li>
            <li>
              <Comment />
            </li>
          </ul>

          從語義角度來看,上面的描述是合理的。

          評論包裝器布局 - 填充解決方案

          我將標題稱為“評論包裝器”,以免混淆評論組件本身的含義。在下一節中,我將解釋我構建布局以處理評論回復的縮進或間距的想法。

          請考慮以下標記:

          <ul>
            <li>
              <!-- Main comment -->
              <Comment />
              <ul>
                <!-- Comment reply -->
                <li>
                  <Comment />
                </li>
              </ul>
            </li>
            <li>
              <Comment />
            </li>
          </ul>

          我們有兩條主評論和一條回復。從視覺角度來看,它將如下所示:

          我更傾向于將所有的間距和縮進處理都保留在 <li> 元素上,因為它們充當了評論組件的容器。

          使data據屬性來處理間距

          我首先考慮的是在 <ul> 和 <li> 元素上使用數據屬性。

          <ul>
            <li nested="true">
              <!-- Main comment -->
              <Comment />
              <ul>
                <!-- Comment reply -->
                <li>
                  <Comment />
                </li>
              </ul>
            </li>
            <li>
              <Comment />
            </li>
          </ul>
          

          在CSS中,我們可以這樣做:

          li[data-nested="true"],
          li[data-nested="true"]
            li {
            padding-left: 3rem;
          }

          雖然前面提到的方法是有效的,但是我們可以通過使用CSS變量和樣式查詢來進一步改進。

          使用CSS樣式變量查詢

          我們可以檢查容器中是否添加了CSS變量--nested: true,并根據此對子元素進行樣式設置。

          考慮以下標記,我在 <ul> 元素中添加了內聯CSS變量--nested: true。

          <ul>
            <li style="--nested: true;">
              <!-- Main comment -->
              <Comment />
              <ul style="--nested: true;">
                <!-- Comment reply -->
                <li>
                  <Comment />
                </li>
              </ul>
            </li>
            <li>
              <Comment />
            </li>
          </ul>

          使用樣式查詢,我可以檢查CSS變量是否存在,并根據其來為 <li> 元素添加樣式。目前,這個特性只在 Chrome 的實驗性版本 Canary 中得到支持。

          @container style(--nested: true) {
            /* Add spacing to the 2nd level <li> items. */
            li {
              padding-left: 3rem;
            }
          }

          你提到為什么我更喜歡使用樣式查詢而不是數據屬性的原因:

          • 更易于理解:樣式查詢采用 @container 語法,簡單的文字描述已經足夠表達其含義。如果容器中有 --nested: true 的 CSS 變量,那么就應用接下來的樣式。
          • 可以組合多個樣式查詢以更好地控制CSS:通過組合多個樣式查詢,我們可以更靈活地控制CSS樣式。
          • 可以與尺寸容器查詢結合使用:如果需要,我們還可以將樣式查詢與尺寸容器查詢結合使用,進一步增強對CSS的控制能力。

          評論包裝器布局 - 使用CSS Subgrid

          另一個解決方案是使用CSS子網格(subgrid)來構建嵌套評論布局。坦率地說,這將需要更多的CSS代碼,但是探索新的CSS特性的潛力是非常有趣的。

          讓我簡要地解釋一下子網格(subgrid)來給您一個概念。考慮以下CSS網格:

          <ul>
            <li class="main">
              <!-- Main comment -->
              <Comment />
              <ul>
                <!-- Comment reply -->
                <li>
                  <Comment />
                  <ul>
                    <li>
                      <Comment />
                    </li>
                  </ul>
                </li>
              </ul>
            </li>
          </ul>
          li.main {
            display: grid;
            grid-template-columns: 3rem 3rem 1fr;
          }

          這將被添加到 <ul> 列表的第一個直接 <li> 元素中。這個網格看起來會像這樣:

          目前,在CSS網格中,不能將主網格傳遞給子項目。在我們的情況下,我希望將網格列傳遞給第一個 <ul>,然后再傳遞給該 <ul> 的 <li>。

          幸好,CSS子網格(subgrid)使得這種操作成為可能。目前,它僅在Firefox和Safari瀏覽器中可用。Chrome瀏覽器也在朝這個方向發展!

          請參考以下示意圖:

          首先,我們需要設置主網格如下所示。我們有3列。

          @container style(--nested: true) {
            li.main {
              display: grid;
              grid-template-columns: 3rem 3rem 1fr;
          
              .comment {
                grid-column: 1 / -1;
              }
            }
          }

          .comment 組件將始終跨越整個寬度。這就是為什么我添加了 grid-column: 1 / -1。這意味著:“從第一列到最后一列,讓評論組件橫跨全部列”。這樣做有助于避免在嵌套的每個深度中手動輸入列號。類似于這樣:

          /* Not good */
          @container style(--nested: true) {
            li.main .comment {
              grid-column: 1 / 4;
            }
          
            ul[depth="1"] .comment,
            ul[depth="2"] .comment {
              grid-column: 1 / 3;
            }

          很好!接下來的步驟是將深度為1的評論放置在主網格內,然后添加子網格并定位內部的 <li> 元素。

          @container style(--nested: true) {
            ul[depth="1"] {
              grid-column: 2 / 4;
              display: grid;
              grid-template-columns: subgrid;
          
              > li {
                grid-column: 1 / 3;
                display: grid;
                grid-template-columns: subgrid;
              }
            }
          }
          

          最后,我們需要定位深度為2的列表(depth=2)。

          @container style(--nested: true) {
            ul[depth="2"] {
              grid-column: 2 / 3;
            }
          }

          這個解決方案確實有效,但我對其中所有的細節并不太喜歡。一個簡單的內邊距就可以解決問題。

          思考連接線的問題

          為了更清楚地顯示評論和回復之間的關聯,我們可以在主評論和回復之間添加連接線。Facebook團隊使用了一個 <div> 元素來處理這些連接線。但是,我們能否嘗試一些不同的方法呢?

          請參考以下示意圖:

          你的第一反應可能會誤導你:「嗨,這看起來就像一個帶有左邊框和底部邊框以及左下角的邊框半徑的矩形。」

          li:before {
            content: "";
            width: 30px;
            height: 70px;
            border-left: 2px solid #ef5da8;
            border-bottom: 2px solid #ef5da8;
            border-bottom-left-radius: 15px;
          }

          一開始我在上面的CSS代碼中添加了height:..,但我意識到這樣做不行。因為我無法準確知道連接線的高度。這是因為在CSS中無法直接根據內容動態調整高度。問題出在這里:我需要確保連接線的底部與第一個回復的頭像對齊。

          于是我想到可以使用偽元素來實現這個目的。如果那條彎曲的連接線可以分成兩部分呢?

          我們可以將連接線添加到主評論上,而彎曲的元素則用于表示回復。

          接下來,如果我們有另一個回復針對第一個回復呢?以下是一個圖示,展示了連接線是如何運作的:

          在CSS中,我們需要使用偽元素來實現連接線的效果。在開始編寫CSS代碼之前,我想強調一下,這條線或彎曲部分將根據整行來定位。

          處理添加到主評論的連接線

          這是我們要解決的第一個挑戰。如果主評論有回復,我們需要為其添加連接線。我們可以使用CSS的 :has 偽類來檢查一個 <li> 元素是否包含一個 <ul>,如果是,則應用所需的CSS樣式。

          請參考以下HTML代碼:

          <ul style="--depth: 0;">
            <li style="--nested: true;">
              <Comment />
              <ul style="--depth: 1;">
                <li>
                  <Comment />
                </li>
              </ul>
            </li>
            <li>
              <Comment />
            </li>
          </ul>

          我們需要為每個 <Comment /> 元素應用以下條件的樣式:

          • 它是 <li> 元素的直接子元素
          • <li> 元素有一個 <ul> 作為子元素
          • 父元素的 depth 屬性為 0 或 1

          下面是如何將上述條件翻譯為CSS代碼。CSS變量 + 樣式查詢 + :has 偽類=一個強大的條件樣式。

          @container style(--depth: 0) or style(--depth: 1) {
            li:has(ul) > .comment {
              position: relative;
          
              &:before {
                content: "";
                position: absolute;
                left: calc(var(--size) / 2);
                top: 2rem;
                bottom: 0;
                width: 2px;
                background: #222;
              }
            }
          }

          上面的例子展示了為什么我更喜歡使用樣式查詢而不是HTML數據屬性來處理評論和回復的深度。

          接下來,我們需要為深度為1的回復添加連接線和彎曲元素。這次,我們將使用 <li> 元素的 :before 和 :after 偽元素。

          @container style(--depth: 1) {
            li:not(:last-child) {
              position: relative;
          
              &:before {
                /* Line */
              }
            }
          
            li {
              position: relative;
          
              &:after {
                /* Curved element */
              }
            }
          }

          最后,我們需要為深度為2的每個 <li> 添加彎曲元素,同時在深度為2的所有 <li> 中除了最后一個之外,都需要添加連接線。我們需要按照以下邏輯進行操作:

          • 為深度為2的每個 <li> 添加彎曲元素。
          • 為深度為2的所有 <li> 中除了最后一個之外的每個 <li> 添加連接線。

          彎曲元素是一個帶有邊框和左下角半徑的矩形。讓我來解釋一下:

          @container style(--depth: 2) {
            li {
              position: relative;
          
              &:after {
                content: "";
                position: absolute;
                inset-inline-start: 15px;
                top: -2px;
                height: 20px;
                width: 28px;
                border-inline-start: 2px solid #000;
                border-bottom: 2px solid #000;
                border-end-start-radius: 10px;
              }
            }
          
            li:not(:last-child) {
              &:before {
                /* Line */
              }
            }
          }

          請注意,我在邊框(border)和邊框圓角(border-radius)方面使用了邏輯屬性。這樣做有助于在文檔語言為RTL(從右到左)時動態翻轉用戶界面。我將在文章后面詳細介紹這個內容。

          禁用連接線

          如果出于某種原因我們需要隱藏連接線,那么通過樣式查詢(style queries)來實現這一點就像切換CSS變量的開關一樣簡單。

          通過將所有與深度相關的樣式查詢嵌套在 --lines: true 的樣式查詢內部,我們可以確保只有在設置了該 CSS 變量時才會顯示連接線。

          @container style(--lines: true) {
            @container style(--depth: 0) {
            }
          
            @container style(--depth: 1) {
            }
          
            @container style(--depth: 1) {
            }
          
            @container style(--depth: 2) {
            }
          }

          評論組件

          你可能會認為上面所有的內容都只是用于主要的布局和連接線。是的,沒錯!我甚至還沒有考慮評論組件。

          讓我們仔細看一下評論組件:

          乍一看,這似乎是使用 flexbox 的絕佳場景。我們可以通過 flexbox 將頭像和評論框顯示在同一行上。

          <div class="comment">
            <div class="user"></div>
            <!-- Because an additional wrapper doesn't hurt. -->
            <div>
              <div class="comment__body"></div>
              <div class="comment__actions">
                <a href="#">Like</a>
                <a href="#">Reply</a>
              </div>
            </div>
          </div>

          請注意,上面的HTML代碼非常基礎,它并不代表生產級別的代碼,只是用來幫助解釋CSS的內容。

          .comment {
            --size: 2rem;
            display: flex;
            gap: 0.5rem;
          }
          
          .avatar {
            flex: 0 0 var(--size);
            width: var(--size);
            height: var(--size);
            border-radius: 50%;
          }
          

          這是基本的布局,但實際應用中可能會更加復雜。然而,在本文中,我將僅專注于需要解釋的獨特和重要的內容。

          接下來,我們會討論評論主體組件的一些考慮事項。

          評論組件的這部分將需要處理以下內容:

          • 最小寬度
          • 長內容
          • 多語言內容(左到右 vs 右到左)
          • 上下文菜單
          • 評論交互
          • 編輯狀態
          • 錯誤狀態

          我在這篇文章中無法詳細展示上述所有內容,因為可能需要寫一本書來完整講述。

          我將重點介紹一些我認為適合使用現代CSS的有趣技巧。

          改變用戶頭像大小

          在回復嵌套在評論中時,用戶頭像的大小將變小。這樣做有助于在視覺上更容易區分主評論和回復。

          使用樣式查詢是非常適合這種情況的。

          .user {
            flex: 0 0 var(--size);
            width: var(--size);
            height: var(--size);
          }
          
          .comment {
            --size: 2rem;
          
            @container style(--depth: 1) or style(--depth: 2) {
              --size: 1.5rem;
            }
          }

          動態文本對齊與 dir=auto 屬性

          評論可能包含從左到右(LTR)或從右到左(RTL)的語言。根據內容的語言,文本對齊應該有所區別。感謝 dir=auto HTML 屬性,我們可以讓瀏覽器自動處理這一點。

          <div class="comment">
            <div class="user"></div>
            <div>
              <div class="comment__body">
                <p dir="auto"></p>
              </div>
              <div class="comment__actions"></div>
            </div>
          </div>

          CSS 邏輯屬性

          通過使用 CSS 邏輯屬性,我們可以構建評論組件,使其能根據文檔的方向進行自適應調整。同樣的原理也適用于連接線。

          表情符號回復狀態

          當用戶添加僅由表情符號組成的評論時,評論容器將會有一些變化:

          • 沒有背景顏色
          • 沒有內邊距

          這是使用CSS :has偽類的一個絕佳用例。

          .comment:has(.emjois-wrapper) {
            background: var(--default);
            padding: var(--reset);
          }

          結論

          現代CSS的潛力一直讓人興奮不已。嘗試用新的方式思考已經構建的組件或布局,是學習新知識的絕佳途徑。我在整個過程中學到了很多新東西,并享受了整個過程。

          由于文章內容篇幅有限,今天的內容就分享到這里,文章結尾,我想提醒您,文章的創作不易,如果您喜歡我的分享,請別忘了點贊和轉發,讓更多有需要的人看到。同時,如果您想獲取更多前端技術的知識,歡迎關注我,您的支持將是我分享最大的動力。我會持續輸出更多內容,敬請期待。


          者:Ahmad

          譯者:飄飄

          https://ishadeed.com/article/image-techniques/


          主站蜘蛛池模板: 亚洲综合无码精品一区二区三区| 无码国产精品一区二区免费虚拟VR| 无码精品人妻一区二区三区影院| 无码欧精品亚洲日韩一区夜夜嗨| 免费无码一区二区三区蜜桃大| 亚洲熟女www一区二区三区| 国产乱码一区二区三区四| 人妻免费一区二区三区最新| 少妇无码一区二区二三区| 中文字幕无码一区二区免费| 2021国产精品一区二区在线 | 亚洲国产美国国产综合一区二区 | 久久精品一区二区三区AV| 无码国产精品一区二区免费式直播 | 久久91精品国产一区二区| 亚洲国产成人久久一区久久| 色综合久久一区二区三区| 伊人色综合一区二区三区 | 无码播放一区二区三区| 激情亚洲一区国产精品| 一本大道在线无码一区| 国产在线精品一区二区三区不卡| 亚洲综合一区二区精品导航| 欧洲亚洲综合一区二区三区| 51视频国产精品一区二区| 国产一区二区三区久久| 国产精品久久无码一区二区三区网| 变态拳头交视频一区二区| 91视频一区二区三区| 色综合视频一区二区三区| 久久精品亚洲一区二区| 一区二区高清视频在线观看| 国产区精品一区二区不卡中文| 中文字幕乱码一区久久麻豆樱花| 免费一区二区三区| 中文字幕在线无码一区| 免费日本一区二区| 老鸭窝毛片一区二区三区| 波多野结衣中文一区| 亚洲午夜精品一区二区公牛电影院| 国产视频一区在线观看|