搶先體驗!超強的 Anchor Positioning 錨點定位

来源:https://www.cnblogs.com/coco1s/archive/2023/08/15/17630048.html
-Advertisement-
Play Games

本文,將向大家介紹 CSS 規範中,最新的 Anchor Positioning,翻譯為**錨點定位**。 Anchor Position 的出現,極大的豐富了 CSS 的能力,雖然語法稍顯複雜,但是有了它,能夠實現非常多之前實現起來非常困難,或者壓根無法使用純 CSS 實現的功能。 Anchor ...


本文,將向大家介紹 CSS 規範中,最新的 Anchor Positioning,翻譯為錨點定位

Anchor Position 的出現,極大的豐富了 CSS 的能力,雖然語法稍顯複雜,但是有了它,能夠實現非常多之前實現起來非常困難,或者壓根無法使用純 CSS 實現的功能。

Anchor Position 當前仍屬於實驗室功能,新版本 Chrome 開啟該功能:

  1. 瀏覽器 URL 輸入框輸入: chrome://flags/
  2. 找到 Experimental Web Platform features 選項,開啟該功能

何為 Anchor Positioning?

那麼,什麼是 Anchor Positioning 呢?

Anchor Positioning 由規範 CSS Anchor Positioning 提出定義。

規範是這麼描述的:CSS absolute positioning allows authors to place elements anywhere on the page, without regard to the layout of other elements besides their containing block. This flexibility can be very useful, but also very limiting—often you want to position relative to some other element. Anchor positioning (via the anchor functions anchor() and anchor-size()) allows authors to achieve this, "anchoring" an absolutely-positioned element to one or more other elements on the page, while also allowing them to try several possible positions to find the "best" one that avoids overlap/overflow.

簡單翻譯一下,其核心就在於,Anchor Positioning(錨點定位) 用於增強元素的絕對定位的能力。Anchor Positioning(錨點定位)允許我們基於其它錨點元素的位置和尺寸去定位上下文,而不是傳統意義上的基於父元素去進行絕對定位。

整個 Anchor Positioning 到底是幹啥的?其重點總結如下:

  1. 首先,錨點定位,需要我們通過新的錨點名稱(anchor-name)來標記元素,允許我們使用這些經過了標記的元素作為我們絕對定位的基準目標;
  2. 其次,我們可以在絕對定位的元素上,通過新的語法 anchor() 或者 anchor-size() 來錨定上述被標記了的元素,並且可以使用被標記元素的相應屬性(譬如被標記元素的 top、left、right、bottom 等)
  3. 並且,還有一些更高級的用法,譬如錨點定位的 Fallback 機制,也就是可以設置多套不同的錨點定位規則,以適應更為複雜的頁面佈局情況

下麵,我們通過一個最簡單的例子,快速理解,到底什麼是錨點定位。

假設,我們有如下代碼結構:

<div class="g-container">
    <div class="g-use-anchor"></div>  
    <div class="g-anchor-element"></div>  
</div>
.g-container {
    position: relative;
    width: 50vw;
    height: 50vh;
    border: 2px solid #666;
    display: flex;
    
    .g-anchor-element {
        width: 25vw;
        height: 25vh;
        border: 2px dashed #333;
        margin: auto;
    }
    
    .g-use-anchor {
        position: absolute;
        width: 20px;
        height: 20px;
        background: #fc0;
        border-radius: 50%;
    }
}

整個,會是這麼個效果:

需要簡單解讀一下這個結構:

這個很好理解,註意,此時此刻,.g-use-anchor 由於是絕對定位,是相對於它的父容器 .g-container 進行定位的

而 Anchor Positioning 錨點定位,就允許我們,在上述情況下,改變 .g-use-anchor 的絕對定位的基準元素,允許它在絕對定位下,不再相對於父容器定位,而是相對於設定了 anchor-name 的錨點元素進行定位。

所以,下麵,我們嘗試將 .g-anchor-element 變成一個錨點元素。

代碼如下:

.g-container {
    position: relative;
    width: 50vw;
    height: 50vh;
    border: 2px solid #666;
    display: flex;
    
    .g-anchor-element {
        width: 25vw;
        height: 25vh;
        border: 2px dashed #333;
        margin: auto;
        anchor-name: --target;
    }
    
    .g-use-anchor {
        position: absolute;
        width: 20px;
        height: 20px;
        background: #fc0;
        border-radius: 50%;
        top: anchor(--target top);
        left: anchor(--target left);
    }
}

上面的代碼,有哪些改動呢?

  1. 我們給 .g-anchor-element 添加了一句 CSS 代碼,anchor-name: --target,其含義為,將此元素設定為一個錨點元素,它的名字是 --target
  2. .g-use-anchor 中,新增了兩句代碼
  • top: anchor(--target top):這裡的意思是,使用 name 為 --target 的錨點元素作為定位基準,並且將元素的頂部(top)對齊到錨點元素的頂部(top)
  • left: anchor(--target left):同理,使用 name 為 --target 的錨點元素作為定位基準,並且將元素的左邊(left)對齊到錨點元素的左邊(left)

如此一來,我們就得到了這麼一個效果:

也就是這麼一層關係:

完整的代碼,你可以戳這裡:CodePen Demo -- Anchor Positioning Demo

到這裡,聰明的你應該能夠深刻體會到,上面我們說的這一句話的含義了:

Anchor Positioning(錨點定位) 用於增強元素的絕對定位的能力。Anchor Positioning(錨點定位)允許我們基於其它錨點元素的位置和尺寸去定位上下文,而不是傳統意義上的基於父元素去進行絕對定位。

Anchor Positioning 錨點定位實戰 -- 彈出框定位

可以說,很多之前無法使用 CSS 實現的功能,因為 Anchor Positioning,迎來了新的轉機。

首先,我們來看這麼一個功能點,我們的頁面有很多需要 Hover 的時候彈出的 Popover 或者 Tooltip,像是這樣:

每次 Hover 的時候,彈出框的位置,其實都是需要實時通過 JavaScript 進行計算的。但是在有了 Anchor Positioning 後,我們可以把每一個被 Hover 需要彈出彈出框的元素,都設置成一個錨點元素,而我們的彈出框,只需要在 Hover 的時候,基於當前的錨點元素進行定位即可。

聽起來很複雜,我們來實現一遍試試:

<p class="g-container">
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Quod, porro, <span>facere</span>, et incidunt error aliquam fugit pariatur eos labore ipsum voluptate magni culpa reiciendis optio at accusantium non! Quis, laboriosam.
    Lorem ipsum dolor sit, <span>amet consectetur</span> adipisicing elit. Error commodi sequi perspiciatis ipsa veniam, aut, aliquam maiores quasi <span>adipisci tenetur </span>reiciendis dolor nihil aperiam labore, sunt qui ullam aspernatur <span>voluptate</span>.
</p>

<p> 元素下,被包裹了 <span> 的文字就是需要 Hover 的時候彈出內容的元素。


p {
    position: relative;
    
    span {
        color: deeppink;
    }
    
    &::before,
    &::after {
        position: absolute;
        transition: 0;
        opacity: 0;
    }
    
    &::before {
        content: "";
        top: calc(anchor(var(--target) top) + 10px);
        left: calc(anchor(var(--target) left) + 5px);
        border: 8px solid transparent;
        border-bottom: 8px solid #000;
    }
    &::after {
        content: "Alert Tips!";
        width: 80px;
        padding: 2px 4px;
        font-size: 14px;
        background: #fff;
        border: 2px solid #000;
        top: calc(anchor(var(--target) top) + 24px);
        left: anchor(var(--target) left);
        right: anchor(var(--target) right);
    }
}

p span:nth-child(1) {
    anchor-name: --anchor-1;
}
p span:nth-child(2) {
    anchor-name: --anchor-2;
}
p span:nth-child(3) {
    anchor-name: --anchor-3;
}
p span:nth-child(4) {
    anchor-name: --anchor-4;
}

p:has(span:nth-child(1):hover) {
    --target: --anchor-1;
}
p:has(span:nth-child(2):hover) {
    --target: --anchor-2;
}
p:has(span:nth-child(3):hover) {
    --target: --anchor-3;
}
p:has(span:nth-child(4):hover) {
    --target: --anchor-4;
}

p:has(span:hover)::before,
p:has(span:hover)::after{
    opacity: 1;
}

這裡的代碼,有點長,簡單解釋一下:

  1. 通過 <p> 元素的兩個偽元素 ::before::after,實現了彈出框的框體和一個小三角形
  2. 給每個 <span> 都設置了成了錨點,也就是這麼一段代碼:p span:nth-child(1) {anchor-name: --anchor-1;}
  3. 關鍵來了,利用了 :has 選擇器,實現了當哪個 <span> 被 hover,則設置 --target 變數為當前元素的 anchor-name,也就是實現了錨點元素的動態變換
  4. 最終,只需要讓彈出框(也就是兩個偽元素),基於 --target 進行定位即可,而 --target 元素,就是我們每次 Hover 的文字元素,那麼彈框也就實現了動態定位

知識補充,:has 選擇器變相讓 CSS 擁有了父選擇器的能力,此選擇器用於選擇包含指定子元素的父元素,而本例中,利用了 :has 選擇器甚至能選擇包含指定偽類狀態的能力,實現了 --target 的動態切換。

這樣,我們就成功了實現了上述的功能:

當然,這裡還需要繼續補充一個基於 anchor() 方法的基礎知識,anchor() 方法的值也能與 calc 搭配使用,因此,需要理解如下的表達式:

  • top: calc(anchor(var(--target) top) + 10px):將彈框元素的頂部(top)對齊到錨點元素的頂部(top),再加上 10px 的向上間距
  • left: calc(anchor(var(--target) left) + 5px):將彈框元素的左邊(left)對齊到錨點元素的左邊(left),再加上 5px 的左間距

還有,如果頁面內有 100個 <span> 那下麵這樣的代碼將會是噩夢性的重覆工作:

p span:nth-child(1) {
    anchor-name: --anchor-1;
}
p span:nth-child(2) {
    anchor-name: --anchor-2;
}
p span:nth-child(3) {
    anchor-name: --anchor-3;
}
p span:nth-child(4) {
    anchor-name: --anchor-4;
}

p:has(span:nth-child(1):hover) {
    --target: --anchor-1;
}
p:has(span:nth-child(2):hover) {
    --target: --anchor-2;
}
p:has(span:nth-child(3):hover) {
    --target: --anchor-3;
}
p:has(span:nth-child(4):hover) {
    --target: --anchor-4;
}

因此,我們需要藉助 SCSS/SASS/LESS 等預處理簡化代碼,譬如這樣:

@for $i from 1 to 100 {
    p:has(span:nth-child(#{$i}):hover) {
        --target: --anchor-#{$i};
    }
    p span:nth-child(#{$i}) {
        anchor-name: --anchor-#{$i};
    }
}

合理利用預處理器的迴圈等功能,能有效提升我們的編碼效率。

OK,完整的代碼,你可以戳這裡:

CodePen Demo -- Anchor Positioning Demo

Anchor Positioning 錨點定位實戰 -- Tab 切換下劃線跟隨效果

OK,我們繼續,再來一個有意思的實戰演練。

基於 Anchor Positioning,能否實現這樣一個 TAB 切換時候的,下劃線跟隨效果呢?

此類效果,在之前,一定是需要 JavaScript 的介入才可能實現的。在很久之前,我嘗試使用 CSS 實現過類似的效果:不可思議的CSS導航欄下劃線跟隨效果,效果上有很多瑕疵:

而有了 Anchor Positioning 後,我們將可以完美的實現 Tab 切換過程中的下劃線跟隨效果。

假設,我們的 TAB 的結構如下:

<ul>
    <li>下</li>
    <li>劃</li>
    <li>線</li>
    <li>跟</li>
    <li>隨</li>
    <li>動</li>
    <li>畫</li>
</ul>

其核心流程和上面的彈出框流程非常類似:

  1. 下劃線通過 <ul>元素的偽元素實現
  2. 給每個 <li> 都設置了成了錨點
  3. 利用了 :has 選擇器,實現當任意一個 <li> 被 hover,則設置 --target 錨點變數為當前的 <li> 元素,也就是實現了錨點元素的動態變換
  4. 最終,只需要讓下劃線,基於動態的錨點進行定位即可,也就是我們每次 Hover 的 li 元素,那麼彈框也就實現下劃線動態定位
  5. 給下劃線的 left 設置過渡效果 transition,實現跟隨動畫效果

讓我們一起來看看代碼,看似複雜,代碼量也很少:

ul {
    position: relative;
    width: 700px;
    display: flex;
    
    li {
        flex-grow: 1;
    }
    
    &::before {
        position: absolute;
        content: "";
        height: 5px;
        background: transparent;
        bottom: 0;
        left: anchor(var(--target) left);
        right: anchor(var(--target) right);
        transition: .3s all;
        transform: scaleX(5);
    }
}

ul:hover::before {
    background: #000;
    transform: scaleX(1);
}

@for $i from 1 to 8 {
    ul:has(li:nth-child(#{$i}):hover) {
        --target: --anchor-#{$i};
    }
    li:nth-child(#{$i}) {
        anchor-name: --anchor-#{$i};
    }
}

需要好好理解一下這段代碼,其本質就在於,Hover 的時候,利用 :has 動態改變了 --target 錨點元素,讓偽元素實現的下劃線的寬度,設置為錨點的寬度

並且,這裡還加了一個 hover 過程中 transform: scaleX(5)transform: scaleX(1) 的變化,屬於錦上添花,刪掉不影響最終效果。

當然,也利用了 SCSS 迴圈,減少了代碼量。最終的效果就如我們上面 Gif 圖演示般:

並且,可以做到適配 Flex 彈性佈局各種情況。

這樣,我們就實現了在之前,完全不敢想象能夠由 CSS 獨立實現的功能,完整的代碼,你可以戳這裡:CodePen Demo -- Anchor Positioning Demo

相容性

OK,大家肯定非常關係如此強大的功能的相容性。

目前,Anchor Positioning 還處於較早期的版本,甚至乎我在 Can i Use 上還查不到它的相容性:

但是,目前我使用的 Chrome 115.0.5790.102 是能夠跑通上面的所有代碼。

Anchor Position 當前仍屬於實驗室功能,新版本 Chrome 開啟該功能:

  1. 瀏覽器 URL 輸入框輸入: chrome://flags/
  2. 找到 Experimental Web Platform features 選項,開啟該功能

並且,Anchor Positioning 還有非常多的語法以及有意思的實戰技巧,在本文是沒有放出來的。我會在 Anchor Positioning 相容性更加明朗後,補充一篇更為詳細的教學文章。只能說,未來可期。

最後

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

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

-Advertisement-
Play Games
更多相關文章
  • 簡介 Timescale Documentation | Getting started with Timescale Timescale是一個用於時間序列,事件和分析的PostgreSQL數據平臺。 提供了PostgreSQL的可靠性,這是時間序列的超能力 TimescaleDB,。它提供 自動備 ...
  • GaussDB(for Influx)推出了單機版方案,可用於開發、測試等場景,既能享受到服務化帶來的便利,也可以明顯地降低使用成本。 ...
  • 說到分散式事務,大家並不陌生。在實際工作中,用得比較多的還是柔性分散式事務,今天主要把在工作中運用到的幾種柔性分散式事務的場景及實現方式做一個簡單介紹,也可以看做是柔性分散式事務的一個演進過程。 ...
  • 本文是一次工作中對併發問題的處理案例,問題發生在快遞分揀的流程中,我儘可能將業務背景簡化,讓大家只關註併發問題本身。 ...
  • 本文從EXPLAIN分析SQL的執行計劃開始,進行示例展示,並對輸出結果進行解讀,同時總結了EXPLAIN可產生額外的擴展信息以及EXPLAIN的估計查詢性能,整篇文章基於MySQL 8.0編寫,理論支持MySQL 5.0及更高版本。 ...
  • 博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ...
  • > 😂 好久前寫了關於 `getStaticProps` 和 `getStaticPaths` 的內容,然而半年過去了源碼解析就一直忘記了,不久前有人提醒才想起來,補下坑。 本文主要是解讀下 `getStaticProps`、`getStaticPaths` 相關的源碼,不瞭解這兩個 `API` ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、需求 微信掃碼授權,如果允許授權,則登錄成功,跳轉到首頁。 二、問題 1、微信掃碼授權有幾種實現方式? 2、說一下這幾種實現方式的原理是什麼? 3、vue中的微信掃碼授權登錄,與uniapp和原生小程式的微信授權登錄,它們之間有共同點 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...