TML 5.2<dialog>為本機模態對話框引入了一個新元素。乍一看,它看起來相當簡單(而且確實如此),但是當我一直在玩它時,我發現它有一些很容易錯過的好功能。
在本文末尾提供了一個完整的工作演示,
這是基本對話框的標記:
該open屬性表示該對話框可見。沒有它,對話框將被隱藏,直到您使用JavaScript來顯示它。在添加任何樣式之前,對話框呈現如下:
它絕對位于頁面上,因此它會像您期望的那樣出現在其他內容的前面,并且水平居中。默認情況下,它與內容中的內容一樣寬。
基本操作
JavaScript有一些方法和屬性可以輕松地使用<dialog>元素。你可能最需要的兩種方法是showModal()和close()。
當您使用showModal()打開對話框時,會向頁面添加背景,阻止用戶與模態外部的內容進行交互。默認情況下,此背景是完全透明的,但您可以使用CSS顯示它(更多信息如下)。
按Esc將關閉對話框,您可以提供關閉按鈕來觸發該close()方法。
還有第三種方法,show()也可以使模態出現,但沒有伴隨的背景。用戶仍然可以與對話框外可見的元素進行交互。
目前,<dialog>Chrome只支持行為。Firefox提供默認樣式,但JavaScript API僅在標志后面啟用。我懷疑Firefox很快會默認啟用它。
值得慶幸的是,有既提供JavaScript行為,又提供具有默認樣式的樣式表。dialog-polyfill在npm中安裝以使用它 - 或使用常規舊<script>標簽。它適用于IE9及以上版本。
使用polyfill時,頁面上的每個對話框都需要初始化:
這不會取代擁有它的瀏覽器的本機行為。
打開和關閉模態很不錯,但最初它看起來不太專業。添加樣式就像設置任何其他元素一樣簡單。可以使用新的::backdrop偽元素設置背景樣式。
對于使用polyfill的舊瀏覽器,此偽元素選擇器將不起作用。在其位置,polyfill會.backdrop在對話框后立即添加元素。您可以使用CSS來定位它:
添加一點標記以提供樣式掛鉤。對話框的常用方法是將其分解為標題,正文和頁腳:
為此添加一些CSS,您可以根據需要制作模態外觀:
通常,我們希望從對話框中獲得某種用戶反饋。關閉對話框時,可以將字符串值傳遞給close()方法。此值分配給returnValue對話框DOM元素的屬性,因此可以在以后讀取:
還有一些你可以聽的活動。兩個有用的是close(當模態關閉cancel時觸發)和(當用戶按下Esc以關閉模態時觸發)。
似乎缺少的一件事是在單擊背景時關閉模態的能力,但有一種解決方法。單擊背景會觸發具有<dialog>事件目標的單擊事件。如果構造模態以使子元素填充對話框的整個空間,那么這些子元素將成為對話框內任何單擊的目標。這樣,您可以偵聽對話框上的單擊,并在對話框本身是click事件的目標時關閉它:
這并不完美,但它確實有效。如果您找到更好的方法來檢測背景上的點擊次數,請與我們聯系。
下面是演示地址:http://www.ikinsoft.com/demo/dialog/dialog.html
通訊應用和聊天界面中,當你正在與對方交談時對方正在輸入一條信息,會有一個小的氣泡動畫或者文案提示。本文將探討使用現代 CSS 來實現這一動畫效果,首先會實現一個 Blink 效果的動畫,然后實現一個波浪效果動畫,最后實現一個語音氣泡效果。
1)Blink 效果:
2)Wave 效果:
3)語音氣泡效果:
通過 html:5 和 div.container>(div.dot)*3 快速創建頁面及容器。
<div class="container">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
1)容器居中:
body {
display: grid;
place-content: center;
min-height: 100vh;
margin: 0;
}
2)容器樣式:
注意:此處使用了現代CSS 原生嵌套(參考鏈接:)
.container {
display: flex;
justify-content: center;
align-items: center;
gap: 0.25rem;
background: #e2e8f0;
border-radius: 9999px;
padding: 1rem;
.dot {
border-radius: 9999px;
height: 0.5rem;
width: 0.5rem;
background: #93a2b7;
}
}
1)Blink 效果:
核心思想是通過給dot 元素設置 opacity 設置屬性來改變其透明度,同時對 3 個 dot 的透明度變化設置不同的動畫延遲 animation-delay 屬性來實現閃爍的效果。
.container {
.dot {
opacity: 0;
animation: blink 1s infinite;
&:nth-child(1) {
animation-delay: 0.3333s;
}
&:nth-child(2) {
animation-delay: 0.6666s;
}
&:nth-child(3) {
animation-delay: 0.9999s;
}
}
}
@keyframes blink {
50% {
opacity: 1;
}
}
2)Wave 效果:
核心思想:給 dot 元素增加 transform 屬性,設置 translateY 的值將目標元素從下至上垂直重新定位,同時在動畫關鍵幀 keyframes 中對顏色進行調整。
.container {
.dot {
animation: wave 1s infinite;
}
}
@keyframes wave {
0% {
transform: translateY(0px);
background: rgba(148 163 184 / 0);
}
25% {
transform: translateY(-0.25rem);
background: rgba(148 163 184 / 0.8);
}
50% {
transform: translateY(0px);
background: rgba(148 163 184 / 0);
}
75% {
transform: translateY(0.25rem);
background: rgba(148 163 184 / 0.8);
}
100% {
transform: translateY(0);
background: rgba(148 163 184 / 0);
}
}
2)語音氣泡效果:
語音氣泡是以可視化方式顯示對話或思想的一種流行而有效的方法。你可能在漫畫、卡通、廣告和社交媒體文章中見過它們。它們為設計增添了幽默、情感和個性,同時也為觀眾提供了語境。此外,語音氣泡布局還可以將文字較多的設計分割開來,使其更加吸引人。
核心思想:在 wave 效果的基礎上,對 .contianer 容器增加 ::before 和 ::after 兩個偽元素來實現左下角的圓圈,同時動畫中增加對整個容器的放大和縮小 scale 動畫,并采用 ease-out 函數。
.container {
animation: 2s zoom infinite ease-out;
position: relative;
&::before,
&::after {
content: '';
position: absolute;
border-radius: 9999px;
background: rgb(226 232 240);
bottom: 0;
left: 0;
}
&::before {
height: 1rem;
width: 1rem;
transform: translate(-0.125rem, 0.125rem);
}
&::after {
height: 0.5rem;
width: 0.5rem;
transform: translate(-0.5rem, 0.5rem);
}
.dot {
border-radius: 9999px;
height: 0.5rem;
width: 0.5rem;
background: rgba(148 163 184 / 1);
animation: wave 1.2s infinite;
&:nth-child(1) {
animation-delay: 0.4s;
}
&:nth-child(2) {
animation-delay: 0.8s;
}
&:nth-child(3) {
animation-delay: 1.2s;
}
}
}
@keyframes zoom {
50% {
transform: scale(1.1);
}
}
如果本文對您有幫助,歡迎關注、點贊和轉發,感謝您的支持!
日常工作中,如下圖的聊天場景是不是很熟悉,沒錯就是我們再熟悉不過的 QQ 和微信,一個正常的聊天界面大致上是長這個樣子的:
這種聊天窗口的消息流有兩個明顯的特點:
一般來說要實現這樣的功能,對于前端開發來說都不是難事,只要兩步就可以了:
這樣的 demo 只需要隨手擼二三十行代碼就實現了:
一開始渲染消息 1~20,滾到頂部后渲染第二屏消息 ABCDEFGHIJK,看上去前后兩屏消息的銜接很平滑很流暢。目前開源社區中也有很多現成的用 React 和 Vue 開發的聊天組件或者示例,他們基本也是用上面提到的思路或者借助 iScroll 實現的。
用上面這種思路跑在 Web 中是沒有任何問題的,但是在小程序中的表現卻大失所望,看一下用同樣的方式應用到小程序后的實際效果:
從第一段視頻(左)可以看到從列表進入到聊天頁面后設置滾動條位置到底部發生了明顯的跳動,先看到停留在頂部然后瞬間再去到底部;
第二段視頻(右)滾動到頂部加載后,下一屏消息與當前消息的銜接出現了一個明顯的跳動,也是先看到在頂部然后才去到預期的位置。
為什么這個思路在 Web 端體驗這么好,到了小程序上體驗就如此糟糕呢?原因其實很簡單,這是由于小程序底層通信邏輯和視圖更新機制造成的:
由于小程序跨線程通信和異步更新的特點,內容的渲染和滾動位置的設置無法保證完成的先后順序,所以必然會先看到上一個位置一閃而過的畫面。
既然是底層的問題,那么這種聊天場景在小程序中難道就玩不了了嗎?當然也有嘗試過用 opacity 過渡和滾動動畫去緩解這種跳動,但都無法從根本上解決這兩個體驗問題。
當各種常規方案嘗試都不盡滿意的時候,那就換個思路:從本質上來說,聊天窗口的消息流實際上是一個 “反自然” 的列表,因為在計算機的 “自然界” 和人們習以為常的使用方式上,列表的初始位置都是在最頂部,想要瀏覽列表更多的內容需要向下滾動,而聊天場景的特點是完全反常規的!
再回到這兩個體驗問題:為什么需要手動設置最新消息和滾動條到最底部,為什么不讓它一開始就在底部?為什么需要要在列表頂部追加數據,為什么不讓它在底部追加數據?所以有沒有可能顛倒常規,做一個 “反向渲染” 的滾動列表呢?答案是肯定的!
首先像常規的列表一樣去渲染,不需要做任何處理,第一條最新消息和滾動條的初始位置是自然地在最上面:
然后把整個列表區域的包裹容器用 CSS 旋轉 180°,這樣第一條最新消息和滾動條初始位置就在最下面下了:
不過此時整個列表是倒置渲染的,最后再把每一條消息組件用同樣的方式旋轉 180° 使它們顯示回正常的視角,這樣就實現了一個 “反向渲染” 的列表:
雖然是 “反向渲染”,但視覺上和正常的一模一樣。此時頂部就變成了底部,向上追加數據變成了向下追加數據。最后看一下聊天列表使用 “反向渲染” 之后的體驗效果:
可以看到,下拉加載消息與當前消息的銜接非常平滑沒有任何的跳動,實際上這個時候歷史消息是在底部渲染的,只不過反向渲染讓它看上去是在頂部渲染的;此外,頁面一進來最新消息和滾動條位置無需任何處理自然地停留在最底部,接近原生體驗。
這種 “反向渲染” 的思路用最少的代碼就解決了消息場景在小程序上這種幾乎無解的問題,并且達到了最優的體驗,而實際上核心代碼只有兩行 CSS:
transform: rotate(180deg);
direction: rtl;
整個過程無需任何手動設置滾動位置和計算第二屏總高度(實際上都不用關心它們),同樣這種思路用在 Web 上也是 OK 的。當然用了反向渲染也有一些犧牲,比如 iOS 雙擊頂部欄回到頂部這個特點就不能用了,但總體來說獲得體驗上的優化是更多的。
此外,聊天場景中的消息流通常也有這樣的布局:
如果視覺上需要將自己和別人的消息方向分別位列兩邊對齊,那么利用這種 “反向渲染” 的思路,實現起來也非常容易,只需要對消息組件應用不同的 CSS 樣式即可:
消息流的每一條消息都是一個單獨的組件,此時不需要為了區分不同的視角而去新寫一個組件,也不需要改變現有組件的結構布局。
?? 最后
如果你覺得這篇文章對你有幫助,點個「關注/轉發」,讓更多的人也能看到你的分享!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。