Thông tin tổng quan cơ bản về cách tạo một thành phần thông báo ngắn thích ứng và hỗ trợ tiếp cận.
Trong bài đăng này, tôi muốn chia sẻ suy nghĩ về cách tạo thành phần thông báo ngắn. Hãy dùng thử bản minh hoạ.
Nếu bạn thích xem video, hãy xem phiên bản video của bài đăng này trên YouTube:
Tổng quan
Thông báo ngắn là thông báo ngắn không tương tác, thụ động và không đồng bộ dành cho người dùng. Thông thường, chúng được dùng làm mẫu phản hồi giao diện để thông báo cho người dùng về kết quả của một hành động.
Lượt tương tác
Thông báo ngắn không giống như thông báo, cảnh báo và lời nhắc vì chúng không có tính tương tác; chúng không được đóng hoặc tồn tại. Thông báo dành cho thông tin quan trọng hơn, thông báo đồng bộ yêu cầu tương tác hoặc thông báo cấp hệ thống (thay vì cấp trang). Thông báo ngắn mang tính thụ động hơn so với các chiến lược thông báo khác.
Markup (note: đây là tên ứng dụng)
Phần tử <output>
là một lựa chọn phù hợp cho thông báo ngắn vì thông báo này được thông báo cho trình đọc màn hình. HTML chính xác cung cấp một cơ sở an toàn để chúng ta nâng cao bằng JavaScript và CSS, và sẽ có rất nhiều JavaScript.
Thông báo ngắn
<output class="gui-toast">Item added to cart</output>
Bạn có thể thêm nhiều thành phần hơn bằng cách thêm role="status"
. Điều này cung cấp một phương án dự phòng nếu trình duyệt không cung cấp cho các phần tử <output>
vai trò ngầm ẩn theo thông số kỹ thuật.
<output role="status" class="gui-toast">Item added to cart</output>
Vùng chứa thông báo ngắn
Có thể hiển thị nhiều thông báo ngắn cùng một lúc. Để điều phối nhiều thông báo ngắn, bạn cần sử dụng một vùng chứa. Vùng chứa này cũng xử lý vị trí của thông báo ngắn trên màn hình.
<section class="gui-toast-group">
<output role="status">Wizard Rose added to cart</output>
<output role="status">Self Watering Pot added to cart</output>
</section>
Bố cục
Tôi đã chọn ghim thông báo ngắn vào inset-block-end
của khung nhìn và nếu thêm thông báo ngắn khác, chúng sẽ xếp chồng từ cạnh màn hình đó.
Vùng chứa GUI
Vùng chứa thông báo ngắn thực hiện mọi công việc liên quan đến bố cục để hiển thị thông báo ngắn. Thuộc tính này là fixed
cho khung nhìn và sử dụng thuộc tính logic inset
để chỉ định cạnh nào sẽ được ghim, cùng với một chút padding
từ cùng một cạnh block-end
.
.gui-toast-group {
position: fixed;
z-index: 1;
inset-block-end: 0;
inset-inline: 0;
padding-block-end: 5vh;
}
Ngoài việc tự định vị trong khung nhìn, vùng chứa thông báo ngắn là một vùng chứa lưới có thể căn chỉnh và phân phối thông báo ngắn. Các mục được căn giữa dưới dạng một nhóm bằng justify-content
và được căn giữa riêng lẻ bằng justify-items
.
Thêm một chút gap
để thông báo ngắn không chạm vào.
.gui-toast-group {
display: grid;
justify-items: center;
justify-content: center;
gap: 1vh;
}
Thông báo ngắn trên GUI
Một thông báo ngắn riêng lẻ có một số padding
, một số góc mềm hơn với
border-radius
,
và một hàm min()
để
hỗ trợ định cỡ cho thiết bị di động và máy tính. Kích thước thích ứng trong CSS sau đây ngăn thông báo ngắn hiển thị rộng hơn 90% khung nhìn hoặc 25ch
.
.gui-toast {
max-inline-size: min(25ch, 90vw);
padding-block: .5ch;
padding-inline: 1ch;
border-radius: 3px;
font-size: 1rem;
}
Kiểu
Khi đã thiết lập bố cục và vị trí, hãy thêm CSS để giúp điều chỉnh các chế độ cài đặt và hoạt động tương tác của người dùng.
Vùng chứa thông báo ngắn
Thông báo ngắn không có tính tương tác, việc nhấn hoặc vuốt vào thông báo ngắn sẽ không làm gì cả, nhưng hiện tại, thông báo ngắn sẽ sử dụng các sự kiện con trỏ. Ngăn thông báo ngắn đánh cắp lượt nhấp bằng CSS sau.
.gui-toast-group {
pointer-events: none;
}
Thông báo ngắn trên GUI
Đặt giao diện thích ứng sáng hoặc tối cho thông báo ngắn bằng các thuộc tính tuỳ chỉnh, HSL và truy vấn nội dung đa phương tiện ưu tiên.
.gui-toast {
--_bg-lightness: 90%;
color: black;
background: hsl(0 0% var(--_bg-lightness) / 90%);
}
@media (prefers-color-scheme: dark) {
.gui-toast {
color: white;
--_bg-lightness: 20%;
}
}
Hoạt ảnh
Thông báo ngắn mới sẽ xuất hiện cùng với ảnh động khi vào màn hình.
Bạn có thể điều chỉnh chuyển động giảm bằng cách đặt giá trị translate
thành 0
theo mặc định, nhưng cập nhật giá trị chuyển động thành một độ dài trong truy vấn nội dung đa phương tiện ưu tiên chuyển động . Mọi người đều thấy một số ảnh động, nhưng chỉ một số người dùng thấy thông báo ngắn di chuyển một khoảng cách.
Dưới đây là các khung hình chính dùng cho ảnh động thông báo ngắn. CSS sẽ kiểm soát việc nhập, chờ và thoát của thông báo ngắn, tất cả trong một ảnh động.
@keyframes fade-in {
from { opacity: 0 }
}
@keyframes fade-out {
to { opacity: 0 }
}
@keyframes slide-in {
from { transform: translateY(var(--_travel-distance, 10px)) }
}
Sau đó, phần tử thông báo ngắn sẽ thiết lập các biến và điều phối các khung hình chính.
.gui-toast {
--_duration: 3s;
--_travel-distance: 0;
will-change: transform;
animation:
fade-in .3s ease,
slide-in .3s ease,
fade-out .3s ease var(--_duration);
}
@media (prefers-reduced-motion: no-preference) {
.gui-toast {
--_travel-distance: 5vh;
}
}
JavaScript
Khi đã có sẵn các kiểu và HTML hỗ trợ tiếp cận trình đọc màn hình, bạn cần có JavaScript để điều phối việc tạo, thêm và huỷ thông báo ngắn dựa trên các sự kiện của người dùng. Trải nghiệm của nhà phát triển về thành phần thông báo ngắn phải ở mức tối thiểu và dễ bắt đầu, như sau:
import Toast from './toast.js'
Toast('My first toast')
Tạo nhóm thông báo ngắn và thông báo ngắn
Khi tải từ JavaScript, mô-đun thông báo ngắn phải tạo một vùng chứa thông báo ngắn và thêm vùng chứa đó vào trang. Tôi đã chọn thêm phần tử trước body
, điều này sẽ khiến các vấn đề về việc xếp chồng z-index
khó xảy ra vì vùng chứa nằm phía trên vùng chứa của tất cả phần tử body.
const init = () => {
const node = document.createElement('section')
node.classList.add('gui-toast-group')
document.firstElementChild.insertBefore(node, document.body)
return node
}
Hàm init()
được gọi nội bộ cho mô-đun, lưu trữ phần tử dưới dạng Toaster
:
const Toaster = init()
Bạn có thể tạo phần tử HTML của thông báo ngắn bằng hàm createToast()
. Hàm này yêu cầu một số văn bản cho thông báo ngắn, tạo một phần tử <output>
, trang trí phần tử đó bằng một số lớp và thuộc tính, đặt văn bản và trả về nút.
const createToast = text => {
const node = document.createElement('output')
node.innerText = text
node.classList.add('gui-toast')
node.setAttribute('role', 'status')
return node
}
Quản lý một hoặc nhiều thông báo ngắn
Giờ đây, JavaScript sẽ thêm một vùng chứa vào tài liệu để chứa thông báo ngắn và sẵn sàng thêm thông báo ngắn đã tạo. Hàm addToast()
điều phối việc xử lý một hoặc nhiều thông báo ngắn. Trước tiên, hãy kiểm tra số lượng thông báo ngắn và xem liệu chuyển động có ổn không, sau đó sử dụng thông tin này để thêm thông báo ngắn hoặc tạo một số ảnh động bắt mắt để các thông báo ngắn khác xuất hiện "dành chỗ" cho thông báo ngắn mới.
const addToast = toast => {
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
)
Toaster.children.length && motionOK
? flipToast(toast)
: Toaster.appendChild(toast)
}
Khi thêm thông báo ngắn đầu tiên, Toaster.appendChild(toast)
sẽ thêm thông báo ngắn vào trang kích hoạt ảnh động CSS: ảnh động vào, đợi 3s
, ảnh động ra.
flipToast()
được gọi khi có thông báo ngắn hiện có, sử dụng một kỹ thuật có tên là FLIP của Paul Lewis. Ý tưởng là tính toán sự khác biệt về vị trí của vùng chứa, trước và sau khi thêm thông báo ngắn mới.
Hãy coi đó là việc đánh dấu vị trí hiện tại của Toaster, vị trí sắp tới, sau đó tạo ảnh động từ vị trí hiện tại đến vị trí sắp tới.
const flipToast = toast => {
// FIRST
const first = Toaster.offsetHeight
// add new child to change container size
Toaster.appendChild(toast)
// LAST
const last = Toaster.offsetHeight
// INVERT
const invert = last - first
// PLAY
const animation = Toaster.animate([
{ transform: `translateY(${invert}px)` },
{ transform: 'translateY(0)' }
], {
duration: 150,
easing: 'ease-out',
})
}
Lưới CSS sẽ nâng bố cục lên. Khi thêm một thông báo ngắn mới, lưới sẽ đặt thông báo đó ở đầu và tạo khoảng trống với các thông báo khác. Trong khi đó, ảnh động trên web được dùng để tạo ảnh động cho vùng chứa từ vị trí cũ.
Kết hợp tất cả JavaScript
Khi Toast('my first toast')
được gọi, một thông báo ngắn sẽ được tạo, thêm vào trang
(thậm chí vùng chứa có thể được tạo ảnh động để chứa thông báo ngắn mới), một
lời hứa
sẽ được trả về và thông báo ngắn đã tạo sẽ được
theo dõi để hoàn tất ảnh động CSS (3 ảnh động khung hình chính) cho độ phân giải lời hứa.
const Toast = text => {
let toast = createToast(text)
addToast(toast)
return new Promise(async (resolve, reject) => {
await Promise.allSettled(
toast.getAnimations().map(animation =>
animation.finished
)
)
Toaster.removeChild(toast)
resolve()
})
}
Tôi cảm thấy phần gây nhầm lẫn của mã này nằm trong hàm Promise.allSettled()
và ánh xạ toast.getAnimations()
. Vì tôi đã sử dụng nhiều ảnh động khung hình chính cho thông báo ngắn, để chắc chắn rằng tất cả ảnh động đó đã hoàn tất, mỗi ảnh động phải được yêu cầu từ JavaScript và mỗi lời hứa finished
của chúng được quan sát để hoàn tất.
allSettled
sẽ thực hiện việc đó cho chúng ta, tự giải quyết khi tất cả các lời hứa của hàm này
đã được thực hiện. Việc sử dụng await Promise.allSettled()
có nghĩa là dòng mã tiếp theo có thể tự tin xoá phần tử và giả định thông báo ngắn đã hoàn tất vòng đời. Cuối cùng, việc gọi resolve()
sẽ thực hiện lời hứa cấp cao của Toast để các nhà phát triển có thể dọn dẹp hoặc làm công việc khác sau khi thông báo ngắn xuất hiện.
export default Toast
Cuối cùng, hàm Toast
được xuất từ mô-đun để các tập lệnh khác nhập và sử dụng.
Sử dụng thành phần Thông báo ngắn
Bạn có thể sử dụng thông báo ngắn hoặc trải nghiệm dành cho nhà phát triển của thông báo ngắn bằng cách nhập hàm Toast
và gọi hàm đó bằng một chuỗi thông báo.
import Toast from './toast.js'
Toast('Wizard Rose added to cart')
Nếu nhà phát triển muốn dọn dẹp công việc hoặc bất kỳ việc gì khác, sau khi thông báo ngắn xuất hiện, họ có thể sử dụng tính năng không đồng bộ và chờ.
import Toast from './toast.js'
async function example() {
await Toast('Wizard Rose added to cart')
console.log('toast finished')
}
Kết luận
Giờ thì bạn đã biết cách tôi làm, còn bạn thì sao‽ 🙂
Hãy đa dạng hoá các phương pháp và tìm hiểu tất cả các cách xây dựng trên web. Hãy tạo bản minh hoạ, gửi đường liên kết cho tôi trên Twitter và tôi sẽ thêm bản minh hoạ đó vào phần phối lại của cộng đồng ở bên dưới!
Bản phối lại của cộng đồng
- @_developit bằng HTML/CSS/JS: mã và bản minh hoạ
- Joost van der Schee với HTML/CSS/JS: mã và bản minh hoạ