CSS transition 小技巧!如何保留 hover 的狀態?
通常情況下,hover 是無法儲存狀態的。滑鼠移入觸發額外樣式,一旦移出就還原了。
:hover{ color: red }
這就意味著,如果需要保留hover的狀態,可能就不得不借助JS了,比如下面是[1]的首頁排行榜效果。
這裡的主要互動有以下幾個:
- 滑鼠滑過觸發選中態。
- 滑鼠移出列表後仍然保留上一次的選中態(重點)。
- 預設列表的第一項為選中態。
目前官網的實現也是通過JS實現的,事實上,僅僅通過 CSS也是可以完全做到的,需要用到transition延時的一些小技巧,一起看看吧!
一、滑鼠滑過觸發選中態
所有的一切都離不開佈局。
假設列表HTML是這樣的。
<ul class="list"> <li class="item"> <h3 class="title">將軍,夫人喊你種田了</h3> <p class="sumary">只是在休息室裡打了個盹兒,一睜眼,竟然穿成了古代目不識丁的鄉下胖丫頭。 好吃懶做不說,還在村裡橫行霸道。 十里八鄉沒人願意娶她,好不容易買了個金龜婿,大婚之日竟讓人逃了。 惡霸老爹一怒之下去道上擄了個夫君給她。 就是……爹你擄的是不是有點不太對呀? * 婚後的蘇胖丫很忙。 忙著改造惡霸爹爹與惡霸弟弟。 忙著搶救貌美如花的神將夫君。 忙著養育三個小小惡霸小豆丁。 一不小心,將自己忙成了大燕最位高權重的一品女侯!</p> </li> <li class="item"> <h3 class="title">被奪一切後她封神迴歸</h3> <p class="sumary">【甜爽燃,團寵,玄學】 司扶傾一睜眼,不僅被奪了氣運,人人還讓她滾出娛樂圈。 重活一次,她只想鹹魚躺,誰知現在圈內人只知拉踩營銷,沒點真本事,不好好磨鍊演技,這樣下去還能行?怎麼也得收拾收拾。 司扶傾捏了捏手腕,動了。 後來,網上瘋狂罵她不自量力倒貼鬱曜,造謠她私生活不檢點,而—— 國際天后:今天我能站在這裡,多虧了傾傾 top1男頂流:離我妹妹遠點@鬱曜 就連國際運動會官方:恭喜司扶傾拿下第13枚個人金牌,等一個退圈 當天,全網癱瘓。 · 史書記載,胤皇年少成名,八方征戰,平天下,安宇內,是大夏朝最年輕的帝王,他完美強大,心懷天下,卻因病死於27歲,一生短暫,無妻無妾,無子無孫,是無數人的白月光男神。 無人知曉,他再睜開眼,來到了1500年後。 這一次,他看見了他遙想過的盛世大夏。 · 不久後胤皇身份曝光,司扶傾得知偶像竟然就在身邊,她敬佩萬分,只想—— 司扶傾:努力奮鬥,報效大夏! 胤皇:以身相許 司扶傾:??? 我一心奮發上進你卻想要我? · 全能顏巔女神×殺伐清貴帝王 從全網黑到封神頂流,順便和男神1v1</p> </li> ... </ul>
簡單修飾一下:
.list{ list-style: none; margin: 0; padding: 0; width: 400px; } .item{ position: relative; padding: 10px 10px 10px 34px; cursor: pointer; counter-increment: num; } .title::before{ content: counter(num) ' '; width: 25px; line-height: 30px; text-align: center; color: #fff; position: absolute; font-size: 14px; font-family: fantasy; left: 4px; background: center/100% 100% url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAAA8CAMAAAAe9Wm0AAAAbFBMVEUAAACaov2SnPKXnvaXofiyuvuCjPOgqvi4vfiBjPSyuf6Ml/a0u/21vPtte/F/i/WTnfWNmPiyuv6Ik/Zue/GRnPinr/Wfp/Gyuv6Ml/ebo/KTnfOutfqEj/W3vvpue/G/xfd1gvN8iPRodfBFzp+BAAAAF3RSTlMAECA7U2BgdIiTn6Wsvr+/v9Df39/s/o6+GugAAAGPSURBVHjazdZhk4IgEAZgpS6z8iotPEBF8P//x1tJrTxQlrm5uff7MxubLBtF9sQfp+ywjRCJk+zLhPq6SUwuxokhp4/YT1SUVtWam4nSZObImyA2YXHZ022cYsirOzwYoYti7nJzuMOqeHPNvke5jxgP2DRNNqLSMzQQtXjUtv8cBTWiwqOqohcsKikt8ajkHI+4EGjEBWNnNGJ1jUe1Vp9YJLSSeKRkh0eyC0BdEJIBZ5J/h1TA/6SUOgcgjUdaT6gJQA0CjV85jFrq/ZU/UYtA7HFzG5iA1PcOMnbs0b7tU/mcCAhjO/NE52A8jmXKMHYdnukTzE141vhyGWaSTq97ksMQhOnEF8qYFJvXneDO++lU82VznG0giYDppBVzTTvIffdjZSGFVjA2JHeVuRDbopOC6TrJ7GUSx0a1vYGR8u1kQ5krce5hJAUjlRbuRtuyu8GFVopxZ6OtxW5wObU2P3Ewaby+jya6R7UYO+C3xpICbk3NFhptTToaZ6OtzS/WGm39iUdkmdFFv5pvdNPREWjicTcAAAAASUVORK5CYII=); } .title{ margin: 0; padding: 8px 0; font-weight: normal; } .sumary{ margin: 0; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; color: #666; font-size: 14px; color: 20px; height: 0; } .item::before{ content: ''; position: absolute; inset: 0; border-radius: 8px; opacity: 0; z-index: -1; background: linear-gradient(270deg, rgb(241, 236, 249) 0%, rgba(241, 236, 249, 0) 100%); }
效果如下:
現在加上hover的效果:
.item:hover .title{ color: rebeccapurple; } .item:hover .sumary{ height: 40px; } .item.item:hover::before{ opacity: 1; }
效果如下:
很正常的hover效果,沒什麼特別的,那如何在移出後仍然保留最後的狀態呢?接著往下看。
二、保留 hover 的狀態
實現hover保留狀態需要用到這樣一個小技巧。
比如,給一個元素新增hover樣式。
el:hover{ color: red }
如果我們給這個元素加一個延時。
el{ transition-delay: 1s; }
那麼,在滑鼠移入和移出時都會有延遲。
接著,我們在 hover的時候取消延時。
el:hover{ color: red; transition-delay: 0s; }
那麼,在滑鼠移入的時候會迅速響應,移出的時候仍然會有延遲。
到這裡相信大家都明白了吧,如果把延時設定為足夠大,比如:
el{ transition-delay: 9999s; }
這樣滑鼠在移出後,需要經歷9999s後才會變為原狀,也就相當於保留了hover狀態
原理就是這樣,接下來看看實際應用吧!
三、滑鼠移出列表後仍然保留上一次的選中態
根據上面的原理,我們可以輕鬆的實現在hover後保留狀態,如下:
/* 預設 transition */ .item::before, .item .sumary, .item .title{ transition: 0s 9999s; } /* 每一項hover */ .item:hover .title{ color: rebeccapurple; transition: none; } .item:hover .sumary{ height: 40px; transition: none; } .item.item:hover::before{ opacity: 1; transition: none; }
需要注意的是,由於是transition,所以所有的狀態變化都是需要支援過渡屬性的,比如隱藏sumary這裡用的是height: 0而不是display:none,還有選中的背景色變化,由於background-image不支援過渡,所以換成了::before,然後單獨用opacity控制等等一些細節,效果如下:
這樣在滑鼠離開後,之前狀態仍然是保留的。但是我們只需要保留上一次的,而不是所有的,如何處理呢?
這裡需要換一種思路,可以這麼做,滑鼠在移入整個列表的時候就清除所有的狀態,這樣就只有當前hover的選項才會保留下來,有點類似於JS中的思維,先把所有的.current都移除,再給當前項新增.current,實現如下
/* 清除所有hover */ .list:hover .title{ transition: none; color: #333; } .list:hover .sumary{ transition: none; height: 0; } .list:hover .item::before{ transition: none; opacity: 0; }
這樣就實現了滑鼠移出列表後仍然保留上一次的選中態的功能,有點像單選框的效果,只不過是hover觸發的,效果如下:
四、預設列表的第一項為選中態
下面來實現最後一個功能。
這個相對而言比較容易,需要用到:first-child偽類,可以匹配到第一個元素。
不過需要考慮的是優先順序的問題,這個是預設狀態,許可權應該是最低的,其他hover樣式都應該可以覆蓋它,所以可以放在最前面,如下:
/* 初始狀態(第一個選中) */ .item:first-child .sumary{ height: 40px; } .item:first-child .title{ color: rebeccapurple; } .item:first-child::before{ opacity: 1; } /* 清除所有hover */ /* 每一項hover */
這樣就完美實現了文章開頭的效果。
由於是 CSS 實現,多個列表也是完全複用的。
完整程式碼可以檢視線上 demo:[2] 或者[3]
五、總結一下
以上就是通過純 CSS 實現保留滑鼠滑過樣式的全部技巧了,主要還是對transition-delay的靈活運用,下面總結一下:
- 實現原理的利用transition-delay,讓“還原”的時間足夠長,這樣就實現了保留hover狀態的效果了。
- 單選效果可以在滑鼠移入整個列表的時候就清除所有的狀態,這樣就只有當前hover的選項才會保留下來,有點類似於JS中的思維。
- 需要注意所有屬性必須是支援transition的,比如display:none就不支援transition,需要用其他樣式代替。
當然,整個實現對於 CSS 以及選擇器要求是相當高的,實際專案過程中可能並不如 JS 實現來的快,但是,CSS能夠實現的又何必動用 JS呢?在我看來,JS就應該回歸本職,專心處理資料邏輯互動,視覺方面全部交給CSS就行了,只是現在CSS還不夠強大,實現需要用到很多奇技淫巧,但是,CSS現在已經在變得足夠強大,比如:has偽類,相信未來CSS會越來越美好。
- Spring中實現非同步呼叫的方式有哪些?
- 帶引數的全型別 Python 裝飾器
- 整理了幾個Python正則表示式,拿走就能用!
- SOLID:開閉原則Go程式碼實戰
- React中如何引入CSS呢
- 一個新視角:前端框架們都卷錯方向了?
- 編碼中的Adapter,不僅是一種設計模式,更是一種架構理念與解決方案
- 手寫程式語言-遞迴函式是如何實現的?
- 一文搞懂模糊匹配:定義、過程與技術
- 新來個阿里 P7,僅花 2 小時,做出一個多執行緒永動任務,看完直接跪了
- Puzzlescript,一種開發H5益智遊戲的引擎
- @Autowired和@Resource到底什麼區別,你明白了嗎?
- CSS transition 小技巧!如何保留 hover 的狀態?
- React如此受歡迎離不開這4個主要原則
- LeCun再炮轟Marcus: 他是心理學家,不是搞AI的
- Java保證執行緒安全的方式有哪些?
- 19個殺手級 JavaScript 單行程式碼,讓你看起來像專業人士
- Python 的"self"引數是什麼?
- 別整一坨 CSS 程式碼了,試試這幾個實用函式
- 再有人問你什麼是MVCC,就把這篇文章發給他!