首頁 >web前端 >css教學 >僅CSS的星級等級組件等等! (第1部分)

僅CSS的星級等級組件等等! (第1部分)

William Shakespeare
William Shakespeare原創
2025-03-07 16:38:11299瀏覽

A CSS-Only Star Rating Component and More! (Part 1)

構建星級評分組件是Web開發中的經典練習,已使用多種技術反复實現。通常需要少量JavaScript代碼,但僅使用CSS實現呢?是的,可以!

這是一個僅使用CSS實現的星級評分組件演示。您可以點擊更新評分。

很酷,對吧?除了僅使用CSS外,HTML代碼只是一個單一元素:

<input type="range">

範圍輸入元素是理想的選擇,因為它允許用戶在兩個邊界(最小值和最大值)之間選擇數值。我們的目標是設計這個原生元素,將其轉換為星級評分組件,無需額外的標記或任何腳本!我們還將在最後創建更多組件,敬請關注。

注意: 本文僅關注CSS部分。雖然我盡力考慮了UI、UX和可訪問性方面,但我的組件並不完美。它可能有一些缺點(錯誤、可訪問性問題等),因此請謹慎使用。

<input type="range"> 元素

您可能知道,由於所有默認的瀏覽器樣式以及不同的內部結構,設計原生元素(如輸入元素)有點棘手。例如,如果您檢查範圍輸入元素的代碼,您會在Chrome(或Safari、Edge)和Firefox之間看到不同的HTML。

幸運的是,我們有一些共同的部分,我將依賴這些部分。我將定位兩個不同的元素:主元素(輸入本身)和滑塊元素(您使用鼠標滑動以更新值的那個元素)。

我們的CSS主要如下所示:

input[type="range"] {
  /* 主元素样式 */
}

input[type="range"][i]::-webkit-slider-thumb {
  /* Chrome、Safari和Edge的滑块样式 */
}

input[type="range"]::-moz-range-thumb {
  /* Firefox的滑块样式 */
}

唯一的缺點是我們需要重複滑塊元素的樣式兩次。不要嘗試執行以下操作:

input[type="range"][i]::-webkit-slider-thumb,
input[type="range"]::-moz-range-thumb {
  /* 滑块样式 */
}

這不起作用,因為整個選擇器無效。 Chrome等不理解::-moz-*部分,而Firefox不理解::-webkit-*部分。為簡單起見,在本文中,我將使用以下選擇器:

input[type="range"]::thumb {
  /* 滑块样式 */
}

但是演示包含帶有重複樣式的真實選擇器。介紹足夠了,讓我們開始編碼吧!

主元素樣式(星形)

我們首先定義大小:

input[type="range"] {
  --s: 100px; /* 控制大小 */

  height: var(--s);
  aspect-ratio: 5;

  appearance: none; /* 删除默认浏览器样式 */
}

如果我們認為每顆星都位於一個正方形區域內,那麼對於5星級評分,我們需要寬度等於高度的五倍,因此使用aspect-ratio: 5

該5值也定義為輸入元素的max屬性的值。

<input type="range" max="5">

因此,我們可以依靠新增強的attr()函數(目前僅限Chrome)來讀取該值,而不是手動定義它!

input[type="range"] {
  --s: 100px; /* 控制大小 */

  height: var(--s);
  aspect-ratio: attr(max type(<number>));

  appearance: none; /* 删除默认浏览器样式 */
}</number>

現在您可以通過簡單地調整max屬性來控制星星的數量。這很棒,因為max屬性也被瀏覽器內部使用,因此更新該值將控制我們的實現以及瀏覽器的行為。

這個增強的attr()版本目前僅在Chrome中可用,因此我所有的演示都包含一個後備方案來幫助不支持的瀏覽器。

下一步是使用CSS遮罩來創建星星。我們需要形狀重複五次(或更多次,取決於max值),因此遮罩大小應等於var(--s) var(--s)var(--s) 100%或簡化為var(--s),因為默認情況下高度將等於100%。

&lt;input type=&quot;range&quot;&gt;

您可能會問mask-image屬性是什麼?我想我告訴您它需要一些漸變並不奇怪,但它也可以是SVG。本文是關於創建星級評分組件的,但我希望星形部分保持通用性,以便您可以輕鬆地將其替換為任何您想要的形狀。這就是為什麼我在這篇文章的標題中說“還有更多”。我們稍後將看到如何使用相同的代碼結構獲得各種不同的變體。

這裡有一個演示,展示了星形的兩種不同的實現方式。一種是使用漸變,另一種是使用SVG。

在這種情況下,SVG實現看起來更簡潔,代碼也更短,但請記住這兩種方法,因為漸變實現有時可以做得更好。

滑塊樣式(選中值)

現在讓我們關注滑塊元素。使用最後一個演示,然後單擊星星,並註意滑塊的位置。

好消息是,對於所有值(從最小值到最大值),滑塊始終位於給定星形的區域內,但每個星形的位置不同。如果位置始終相同,而不管值如何,那就更好了。理想情況下,為了保持一致性,滑塊應始終位於星形的中心。

這是一張圖,用於說明位置以及如何更新它。

這些線是每個值的滑塊位置。在左側,我們有默認位置,其中滑塊從主元素的左邊緣移動到右邊緣。在右側,如果我們通過在兩側添加一些空間來限制滑塊的位置到較小的區域,我們將獲得更好的對齊方式。該空間等於一顆星大小的一半,或var(--s)/2。我們可以為此使用填充:

input[type="range"] {
  /* 主元素样式 */
}

input[type="range"][i]::-webkit-slider-thumb {
  /* Chrome、Safari和Edge的滑块样式 */
}

input[type="range"]::-moz-range-thumb {
  /* Firefox的滑块样式 */
}

它更好,但並不完美,因為我沒有考慮滑塊大小,這意味著我們沒有真正的居中。這不是問題,因為我將使用等於1px的寬度使滑塊的大小非常小。

input[type="range"][i]::-webkit-slider-thumb,
input[type="range"]::-moz-range-thumb {
  /* 滑块样式 */
}

滑塊現在是一條細線,位於星形的中心。我使用紅色來突出顯示位置,但在現實中,我不需要任何顏色,因為它將是透明的。

您可能認為我們距離最終結果還很遠,但我們快完成了!缺少一個屬性來完成這個難題:border-image

border-image屬性允許我們使用其outset功能在元素外部繪製裝飾。為此,我使滑塊變小且透明。著色將使用border-image完成。我將使用具有兩種純色的漸變作為源:

input[type="range"]::thumb {
  /* 滑块样式 */
}

我們編寫如下內容:

&lt;input type=&quot;range&quot;&gt;

上述內容意味著我們將border-image的區域從元素的每一側擴展100px,並且漸變將填充該區域。換句話說,漸變的每種顏色將覆蓋該區域的一半,即100px。

你明白邏輯了嗎?我們在滑塊的每一側創建了一種溢出的著色——一種將邏輯地跟隨滑塊的著色,因此每次單擊一顆星時,它都會滑入到位!

現在,讓我們使用一個非常大的值而不是100px:

我們快完成了!著色填充了所有星星,但我們不希望它位於中間,而是位於整個選定星形上。為此,我們稍微更新一下漸變,而不是使用50%,我們使用50% var(--s)/2。我們添加一個等於星形寬度一半的偏移量,這意味著第一種顏色將佔據更多空間,我們的星級評分組件就完美了!

我們仍然可以稍微優化代碼,而不是為滑塊定義高度,我們將它保持為0,並且考慮border-image的垂直outset來擴展著色。

input[type="range"] {
  /* 主元素样式 */
}

input[type="range"][i]::-webkit-slider-thumb {
  /* Chrome、Safari和Edge的滑块样式 */
}

input[type="range"]::-moz-range-thumb {
  /* Firefox的滑块样式 */
}

我們也可以使用圓錐漸變來不同地編寫漸變:

input[type="range"][i]::-webkit-slider-thumb,
input[type="range"]::-moz-range-thumb {
  /* 滑块样式 */
}

我知道border-image的語法不容易理解,我對解釋有點快。但我有一篇非常詳細的文章發表在Smashing Magazine上,我在其中用很多例子剖析了這個屬性,我邀請您閱讀,以便更深入地了解該屬性的工作原理。

我們組件的完整代碼如下:

input[type="range"]::thumb {
  /* 滑块样式 */
}
input[type="range"] {
  --s: 100px; /* 控制大小 */

  height: var(--s);
  aspect-ratio: 5;

  appearance: none; /* 删除默认浏览器样式 */
}

就是這樣!幾行CSS代碼,我們就得到了一個漂亮的星級評分組件!

半星評分

如何將評分粒度設置為半星?這很常見,我們可以通過進行一些調整來完成之前的代碼。

首先,我們將輸入元素更新為以半步而不是全步遞增:

<input type="range" max="5">

默認情況下,步長等於1,但我們可以將其更新為.5(或任何值),然後也將最小值更新為.5。在CSS方面,我們將填充從var(--s)/2更改為var(--s)/4,並且對漸變中的偏移量也執行相同的操作。

input[type="range"] {
  --s: 100px; /* 控制大小 */

  height: var(--s);
  aspect-ratio: attr(max type(<number>));

  appearance: none; /* 删除默认浏览器样式 */
}</number>

兩種實現方式之間的差異是一個二分之一的因子,這也是步長值。這意味著我們可以使用attr()並創建適用於這兩種情況的通用代碼。

input[type="range"] {
  --s: 100px; /* 控制大小 */

  height: var(--s);
  aspect-ratio: attr(max type(<number>));

  appearance: none; /* 删除默认浏览器样式 */

  mask-image: /* ... */;
  mask-size: var(--s);
}</number>

這是一個演示,其中修改步長是您需要做的所有事情來控製粒度。不要忘記,您還可以使用max屬性來控制星星的數量。

使用鍵盤調整評分

如您所知,我們可以使用鍵盤調整範圍滑塊輸入的值,因此我們也可以使用鍵盤來控制評分。這是一件好事,但有一個警告。由於使用了mask屬性,我們不再具有指示鍵盤焦點的默認輪廓,這對依賴鍵盤輸入的用戶來說是一個可訪問性問題。

為了獲得更好的用戶體驗並使組件更易於訪問,最好在焦點時顯示輪廓。最簡單的解決方案是添加一個額外的包裝器:

&lt;input type=&quot;range&quot;&gt;

當內部的輸入具有焦點時,這將具有輪廓:

input[type="range"] {
  /* 主元素样式 */
}

input[type="range"][i]::-webkit-slider-thumb {
  /* Chrome、Safari和Edge的滑块样式 */
}

input[type="range"]::-moz-range-thumb {
  /* Firefox的滑块样式 */
}

嘗試在下面的示例中使用鍵盤來調整這兩個評分:

另一個想法是考慮更複雜的遮罩配置,該配置使元素周圍的小區域保持可見以顯示輪廓:

input[type="range"][i]::-webkit-slider-thumb,
input[type="range"]::-moz-range-thumb {
  /* 滑块样式 */
}

我更喜歡使用最後一種方法,因為它保持了單元素實現,但也許您的HTML結構允許您在父元素上添加焦點,您可以保持遮罩配置簡單。這完全取決於您!

更多示例!

正如我之前所說,我們製作的不僅僅是一個星級評分組件。您可以輕鬆更新遮罩值以使用任何您想要的形狀。

這是一個示例,我使用的是心的SVG而不是星形。

為什麼不是蝴蝶?

這次我使用PNG圖像作為遮罩。如果您不習慣使用SVG或漸變,則可以使用透明圖像。只要您有SVG、PNG或漸變,您就可以使用此方法做任何形狀的事情。

我們可以進一步定制並創建一個像下面的音量控制組件:

在最後一個示例中,我沒有重複特定的形狀,而是使用複雜的遮罩配置來創建信號形狀。

結論

我們從一個星級評分組件開始,最後得到了許多很酷的示例。標題本可以是“如何設計範圍輸入元素”,因為這就是我們所做的。我們在沒有任何腳本或額外標記的情況下升級了一個原生組件,並且只使用了幾行CSS代碼。

你呢?你能想到另一個使用相同代碼結構的漂亮組件嗎?在評論區分享您的示例!

文章系列

  1. 僅CSS的星級評分組件及更多! (第一部分)
  2. 僅CSS的星級評分組件及更多! (第二部分)— 3月7日推出!

以上是僅CSS的星級等級組件等等! (第1部分)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn