構建星級評分組件是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%。
<input type="range">
您可能會問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 { /* 滑块样式 */ }
我們編寫如下內容:
<input type="range">
上述內容意味著我們將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
屬性,我們不再具有指示鍵盤焦點的默認輪廓,這對依賴鍵盤輸入的用戶來說是一個可訪問性問題。
為了獲得更好的用戶體驗並使組件更易於訪問,最好在焦點時顯示輪廓。最簡單的解決方案是添加一個額外的包裝器:
<input type="range">
當內部的輸入具有焦點時,這將具有輪廓:
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代碼。
你呢?你能想到另一個使用相同代碼結構的漂亮組件嗎?在評論區分享您的示例!
以上是僅CSS的星級等級組件等等! (第1部分)的詳細內容。更多資訊請關注PHP中文網其他相關文章!