Công nghệ Frosted Glass mở rộng từ game sang web
(tyleo.com)- Bắt đầu từ frosted acrylic UI của Forza Horizon 3 và Forza Motorsport 7, bài viết tổng hợp quá trình tái hiện hiệu ứng tấm kính tương tự trên web bằng HTML/CSS/JavaScript
- Trọng tâm của hiệu ứng là Gaussian blur; cần dùng đồng thời CSS
backdrop-filtervà-webkit-backdrop-filtercho iOS để giảm khác biệt giữa các trình duyệt - Chỉ làm mờ đơn thuần sẽ khiến bề mặt trông phẳng, nên dùng
box-shadow: insetđể thêm chiều sâu ở mép và subsurface scattering, đồng thời dùng bóng đổ thông thường để tạo cảm giác nổi trên nền - Phản chiếu bề mặt được triển khai bằng cách đặt ảnh tia sáng ở một lớp riêng; dùng
background-attachment: fixedhoặc JavaScript để mô phỏng phản chiếu động theo chuyển động của kính - UI cuối cùng kết hợp các lớp
.glass,.light,.drag-me, thêm bo góc, clipping và màu nền bán trong suốt để hoàn thiện thành một component kính có thể sao chép
Hiệu ứng tấm kính lấy từ UI game
- Mục tiêu là tái hiện bằng HTML kiểu thiết kế frosted acrylic từng thấy qua kinh nghiệm phát triển UI của Forza Horizon 3 và Forza Motorsport 7
- Thành phẩm là một tấm kính có thể kéo thả, bao gồm làm mờ nền, chiều sâu ở mép, phản chiếu ánh sáng, bo góc và lớp màu bán trong suốt
- Phần đầu cung cấp công thức cuối cùng có thể sao chép dùng ngay, sau đó lần lượt xây dựng từng hiệu ứng theo từng bước
Tạo độ mờ nền bằng backdrop-filter
- Cốt lõi của hiệu ứng frosted glass đẹp là Gaussian blur, làm mờ nền để trông như một màn chắn bán trong suốt
- Trong CSS, hiệu ứng được triển khai bằng cách áp dụng
blurchobackdrop-filter - Phần tử kính cơ bản bắt đầu từ một
divđơn giản và class.glassbackdrop-filter: blur(10px)-webkit-backdrop-filter: blur(10px)
- Trên iOS, trừ khi thay đổi sâu các thiết lập riêng, vẫn cần
-webkit-backdrop-filter - Vì
backdrop-filterchỉ mới được các trình duyệt hỗ trợ gần đây, người dùng Internet Explorer sẽ không thể trải nghiệm demo
Tạo chiều sâu bằng mép và bóng đổ
- Nếu chỉ áp dụng
backdrop-filter: blur(10px), kính có thể trông phẳng và đơn điệu - Mép kính được triển khai bằng
box-shadow: insetthay vìborder: 1px solidborderảnh hưởng đến kích thước phần tử và cách bố trí phần tử con- Khi dùng
box-shadow: inset, phần tử con có thể lấp đầy vùng nội dung của kính một cách tự nhiên mà không cần các điều chỉnh như margin âm
- Hai inset shadow màu trắng bán trong suốt được dùng để thể hiện mép kính
- Shadow thứ nhất biểu thị mép kính nhìn thấy từ bên ngoài; trong ví dụ xuất hiện ở mép dưới và mép trái
- Shadow thứ hai biểu thị mép nhìn thấy xuyên qua kính; trong ví dụ xuất hiện ở mép trên và mép phải
- Mép nhìn thấy xuyên qua kính nhận ít ánh sáng hơn, nên được đặt mềm và trong suốt hơn
- Thêm
box-shadowtối thông thường có thể tạo cảm giác kính nổi lên một cách vật lý khỏi nền
Tán xạ ánh sáng và phản chiếu bề mặt
- Cảm giác ánh sáng lan bên trong kính được biểu đạt bằng cách đơn giản hóa
subsurface scattering - Việc triển khai tiếp tục dùng
box-shadow: inset- Hiệu ứng tán xạ ngắn:
inset 0px 0px 10px 5px rgba(255, 255, 255, 0.025) - Hiệu ứng tán xạ sâu hơn:
inset 0px 0px 40px 5px rgba(255, 255, 255, 0.025)
- Hiệu ứng tán xạ ngắn:
- Hiệu ứng này dễ thấy hơn khi kéo kính trên nền tối
- Ngoài cảm giác nền bị làm mờ và khúc xạ, còn thêm đặc tính phản chiếu ánh sáng trên bề mặt kính
- Phản chiếu ánh sáng được triển khai bằng cách trộn ảnh tia sáng vào nền
- Có hướng dẫn YouTube và phần giải thích bằng văn bản có thể tham khảo khi tự tạo ảnh tương tự
- Nếu đưa ảnh trực tiếp vào
background-imagecủa phần tử.glass,backdrop-filtersẽ làm mờ ảnh đó, vì vậy cần dùng một lớp riêng như::before
Biến phản chiếu tĩnh thành động
- Chỉ đặt ảnh tia sáng lên sẽ tạo được phản chiếu, nhưng khi di chuyển kính, ánh sáng có thể trông như bị cố định trên bề mặt kính
- Cách dùng CSS thuần là thêm
background-attachment: fixedvào::before- Cách triển khai này đơn giản nhưng có thể không hoạt động trên mọi nền tảng
- Để hoạt động trên mọi nền tảng, dùng JavaScript để mô phỏng
background-attachment: fixed- Việc thao tác trực tiếp với
::beforebằng JavaScript không hiệu quả, nên dùng phần tửdiv.lightriêng - Gắn thuộc tính
data-js-background-attachment-fixedvào phần tử mục tiêu
- Việc thao tác trực tiếp với
- JavaScript đọc giá trị
getBoundingClientRect()của phần tử mục tiêu ở mỗi frame animation, rồi cập nhậtbackground-positiontheo hướng ngược lại với vị trí trong viewportbackgroundPositionX = -clientRect.xbackgroundPositionY = -clientRect.y
- Vòng lặp lặp lại được chạy bằng
requestAnimationFrame
Cấu trúc HTML/CSS cuối cùng
- HTML cuối cùng của phiên bản JavaScript có cấu trúc đặt
.lightdùng cho phản chiếu ánh sáng và.drag-melà lớp văn bản/màu bên trong.glass
Drag Me
.glassphụ trách hình dạng cơ bản và hiệu ứng thị giác của tấm kính- Áp dụng làm mờ nền bằng
backdrop-filtervà-webkit-backdrop-filter - Áp dụng mép, bóng đổ và hiệu ứng tán xạ bằng nhiều
box-shadow - Dùng
position: relativeđể các lớp con có thể lấp đầy vùng của phần tử cha - Áp dụng bo góc bằng
border-radius: 5px - Dùng
overflow: hiddenđể cắt các phần tử con không tràn ra ngoài góc bo
- Áp dụng làm mờ nền bằng
.lightdùng ảnh tia sáng làm nền lặp lạibackground-image: url(path/to/light.png)background-repeat: repeatbackground-size: 750pxopacity: 0.075- Lấp đầy toàn bộ phần tử cha bằng
position: absolutevà offset0ở bốn hướng - Render phía sau các phần tử con khác bằng
z-index: -1
.drag-mecăn giữa nội dung và tạo lớp kính bán trong suốt có màudisplay: flexalign-items: centerjustify-content: centerheight: 30pxbackground-color: rgba(12, 13, 14, 0.75)
Khác biệt của phiên bản không dùng JavaScript
- Phiên bản không dùng JavaScript sử dụng
.glass::beforethay cho phần tử.lightriêng - Áp dụng ảnh tia sáng vào
::beforevà dùngbackground-attachment: fixedđể tạo phản chiếu cố định theo màn hình - Cách này không hoạt động trên mọi nền tảng; phiên bản JavaScript bù lại bằng cách cập nhật trực tiếp
background-position
1 bình luận
Các ý kiến trên Hacker News
Về mặt thẩm mỹ thì tôi thật sự rất thích, nhưng ở phần rìa có vài chỗ không khớp về mặt vật lý
Từ góc nhìn của một lập trình viên embedded, tôi thấy nó hơi lãng phí. Chẳng phải mỗi client đều phải tính một bộ lọc blur “đắt đỏ” mỗi lần để trộn với phiên bản bị làm mờ của ảnh nền sao?
Có dùng GPU và được tối ưu nên rốt cuộc có thể không tốn kém lắm, nhưng phát triển web ngày nay nhìn chung có vẻ đang đi theo hướng quá cồng kềnh. Ngay cả các site đơn giản cũng tải mất 5 giây, rồi đẩy các xử lý nặng sang phía client; dĩ nhiên đây không phải lỗi của tác giả bài viết này
Tôi lớn lên thời modem 14.4k, nên đã quen nghĩ rằng băng thông mạng khan hiếm và đắt đỏ hơn thời gian CPU rất nhiều
Nếu có thể dễ dàng tính toán ở client, thì tôi cho rằng tải cả ảnh qua Internet còn lãng phí hơn. Để nhận bức ảnh đó, router, server, cả ổ đĩa ở xa đều phải hoạt động; dùng tất cả những thứ đó chỉ để tránh xử lý một lần trên dữ liệu đã nằm sẵn trong RAM của client thì còn đáng tiếc hơn
Vì vậy hoặc bản thân giải trí là lãng phí, hoặc nếu không thì việc dùng thêm tính toán để làm giải trí tốt hơn cũng ổn
Muốn vẽ lại những gì thay đổi trong UI thì dù sao cũng cần tính toán GPU, và một hiệu ứng blur đơn giản có thể được thêm vào khá hiệu quả. Chi phí có khả năng còn thấp hơn animation các đối tượng DOM không được tối ưu thành layer GPU
Nhìn việc ngay cả những site đơn giản nhất hiện nay cũng tải hơn 1MB JavaScript cùng cả đống tracker và ngốn CPU, thì blur cho hiệu ứng thẩm mỹ nằm khá xa phía dưới trong danh sách lãng phí
Nếu có nhiều ảnh độ phân giải cao, băng thông mạng thực tế là hữu hạn, nhất là trong môi trường mobile có vùng phủ sóng không dây kém, thì chắc chắn hiệu năng sẽ tệ hơn so với tính toán cục bộ. Ngày nay CSS/WebGL làm được những việc thật đáng kinh ngạc, còn trước đây để tạo các hiệu ứng như thế này cần rất nhiều hack và đường vòng
Bất kể bản thân hành vi đó có lãng phí hay không, chính lối tư duy này cho thấy một vấn đề lớn hơn của xã hội. Vì sao ta cần cái này, và vì sao lại xem trạng thái không có nó là tệ?
Nghĩ đến quy mô các vấn đề xã hội ngày nay, ai còn quan tâm panel UI có bị làm mờ hay không cơ chứ
Khi thử xem có thể làm gì với shader API mới trên Android, tôi từng tái hiện hiệu ứng Windows 7 Aero Glass và trích xuất một texture “vệt sáng” tương tự
Kết quả rất giống bài viết này, chỉ là tôi không thêm bóng đổ bên trong và tăng độ bão hòa của nền bị làm mờ lên một chút
https://mastodon.social/@grishka/110524476584503201
Nói thật, thứ làm cho tutorial cũng không xuất sắc đến thế. Tôi thích các đường nét sắc hơn của phía Windows 7
Tôi cũng đã nghĩ đến việc chỉnh độ bão hòa và thấy trong các ví dụ khác, nhưng quyết định không dùng trong bài. Ảnh mặt trăng được dùng không có nhiều màu nên có lẽ cũng không khác biệt lớn. Những ai tự tạo hiệu ứng kính nên thử nghiệm cả độ bão hòa
Bản thân phần thực hiện rất xuất sắc, và cách trình bày bằng demo tương tác cũng hay. Kéo cửa sổ lên trên mặt trăng khá thú vị
Tuy nhiên tôi không thích dùng hiệu ứng kính mờ trong thiết kế giao diện người dùng, và khi nó được thêm vào Mac OS thì tôi cảm thấy đó là một bước lùi. Các designer quá dễ bị hiệu ứng này mê hoặc, nhưng thực tế nó không bao giờ lý tưởng. Đặc biệt là khi nội dung phía sau panel là động hoặc do người dùng tạo
Nó giống như brushed metal của thập niên 2010, và thật đáng ngạc nhiên là nó đã rò rỉ từ Windows Vista rồi lan ra khắp nơi
Tất nhiên thiết kế cũng ảnh hưởng đến chức năng, nhưng mục đích chính là làm trải nghiệm người dùng thú vị hơn
Tôi cho rằng skeuomorphism làm giao diện thú vị hơn xu hướng tối giản làm phẳng mọi thứ suốt hơn 10 năm qua. Trang trí thị giác mô phỏng bề mặt và chất liệu trong thế giới thực đem lại sự quen thuộc và dễ tiếp cận. Về mặt thực dụng, flat design khiến khó phân biệt các phần tử và trạng thái, trong khi thời còn nút 3D, brushed metal, kính mờ thì mọi thứ rõ ràng hơn nhiều
Tôi nghĩ giờ con lắc đang quay trở lại. Khi ngày càng nhiều designer tránh vẻ ngoài phẳng, tôi hy vọng UI thân thiện với con người hơn sẽ hồi sinh
Blur thường không phải đáp án đúng, nhưng đôi khi lại là lựa chọn phù hợp
Năm 2008, trước khi CSS hỗ trợ
backdrop-blur, từng có một thử nghiệm CSS tạo hiệu ứng tương tự: https://webdev.andersriggelsen.dk/aero/Cách làm là áp hiệu ứng kính lên một ảnh nền đã được làm mờ sẵn và đặt ở vị trí cố định: https://webdev.andersriggelsen.dk/aero/bgl.jpg
Hiệu năng tốt hơn nhiều so với Gaussian blur theo thời gian thực, nhưng vẫn có nhược điểm là không cho phép ảnh nền động
Khi đó vẫn có thể tạo hiệu ứng kính ngay cả trong một khung có thể chuyển động động. Tôi không nhớ có dùng iframe hay không nên phải tìm lại mã, nhưng xét thời điểm đó thì có lẽ khả năng cao là có dùng
Tôi đang dùng Windows 10 19045.5131, còn Chrome là bản mới nhất Version 131.0.6778.86 (Official Build) (64-bit)
Thành tựu kỹ thuật thì ấn tượng, nhưng tôi xem đây là UX tệ
Nội dung trong các panel bán trong suốt khó đọc hoặc khó hiểu hơn so với trên nền một màu nhất quán; độ tương phản với nền thấp và không đều. Hơn nữa, nếu có thứ gì đó chuyển động bên dưới thì có thể gây xao nhãng và làm mất phương hướng
Nếu tích hợp tốt, cần điều chỉnh cường độ hiệu ứng để UI không bị quá đà, kiểm tra hỗ trợ tính năng để tránh thêm trang trí khi không hỗ trợ blur, và kiểm tra khả năng hiển thị/video để không render trên những thiết bị có khả năng GPU không đủ
Ngoài ra, cần kiểm tra tùy chọn của người dùng để cung cấp nền một màu có độ tương phản tốt cho những người gặp khó với nền phức tạp, giới hạn phạm vi hiệu ứng và bóng đổ theo không gian khả dụng, đồng thời điều chỉnh blur và độ mờ đục dựa trên độ phức tạp và độ tương phản của nền bên dưới vùng mờ
Cũng cần bảo đảm blur và bóng đổ co giãn thích ứng theo typography. Về bản chất, UX là thiết kế cách người dùng trải nghiệm tương tác với toàn bộ ứng dụng, chứ không phải thành bại chỉ vì một lựa chọn phong cách riêng lẻ
Điều đó bảo đảm khả năng đọc của văn bản ngay cả trong trường hợp cực đoan khi nền màu đen. Trong CSS có thể tái tạo bằng thuộc tính
text-shadowTuy nhiên trong game thì có nhiều chỗ dùng hơn. Đặc biệt nó có thể phù hợp với HUD, nơi không muốn che nền là vùng chính mà người dùng tương tác
Độ tương phản tốt là một thách thức với bất kỳ yếu tố thiết kế nào, dù là nền một màu hay hiệu ứng kính
Việc những gì diễn ra ở nền gây xao nhãng và làm mất phương hướng cũng rất chủ quan. Cũng như giảm độ mờ đục của một màu đặc, ta có thể giảm độ bán trong suốt của kính
Khó có thể xem phê bình này là đúng một cách khách quan, và vẫn có cách tích hợp yếu tố thiết kế này trong khi tránh các vấn đề đó. Ảnh chụp màn hình Forza trông ổn, và khi nhìn thực tế thì nền cũng không gây xao nhãng. Đổi lại, ta có một UI thú vị và dễ chịu về mặt thị giác hơn so với nền một màu. Điều này có thể quan trọng hơn trong video game, nhưng cũng có thể dùng tinh tế trong thiết kế OS và web
Nếu cần nhiều ngữ cảnh thì blur không phải lựa chọn tốt; nếu hoàn toàn không cần ngữ cảnh thì cũng không phải lựa chọn tốt
Nhưng đôi khi nó là một lựa chọn tuyệt vời
Ví dụ tương tác thì hay, nhưng nếu có toggle để so sánh song song với bước trước hoặc chuyển qua lại thì có lẽ còn tốt hơn
Ở hầu hết các bước, cải tiến quá tinh tế nên khó nhận ra khác biệt
Có khoảng 10 hiệu ứng chồng lên nhau, và nếu không nhắm tới thẩm mỹ cực kỳ cầu kỳ thì khoảng 7 cái là quá nhiều
Chỉ cần màu nền, blur, bóng đổ hoặc viền là đủ
Chỉ đến bước thứ ba thôi, với blur và bóng đổ, đã có một mảnh kính khá ổn. Cá nhân tôi khuyên nên thêm một ảnh vệt sáng tĩnh vào đó. Tôi nghĩ hầu hết ứng dụng không cần toàn bộ hiệu ứng JavaScript. Nó vui mắt, nhưng có thể gây xao nhãng
Chỉ với blur, bóng đổ và vệt sáng, cũng có thể tiến rất gần tới ảnh Forza ở đầu bài
Tôi nghĩ đó là một trong những lý do mọi người chuyển sang flat design. Windows Vista và hiệu ứng kính rất đẹp, nhưng chi phí tính toán lớn
Flat design gây tranh cãi về mặt thẩm mỹ, và đặc biệt với người dùng lớn tuổi, nó có thể khó dùng hơn thiết kế skeuomorphic [0][1]
Nếu tính hiện thực có thể hỗ trợ khả năng sử dụng, thì việc dùng những hiệu ứng như thế này trên web là hoàn toàn hợp lý
[0]: https://www.tandfonline.com/doi/abs/10.1080/0144929X.2020.18...
[1]: https://www.sciencedirect.com/science/article/abs/pii/S01419...
n <= 3Không rõ đó là vấn đề về khả năng tiếp cận, hiệu năng, bảo trì, hay lý do nào khác
Trong các năng lực phát triển của tôi, CSS là phần yếu nhất áp đảo, nên tôi hoàn toàn không biết đâu là thực hành tốt và đâu là thực hành xấu
Thật thú vị vì có cảm giác mọi thứ đã đi hết một vòng
Một trong những demo CSS đầu tiên, demo cho CSS 1, là hiệu ứng kính mờ: https://meyerweb.com/eric/css/edge/complexspiral/glassy.html
Thành thật mà nói, khá ấn tượng. Lúc nào cũng thú vị khi thấy CSS có thể sáng tạo và mạnh mẽ đến mức nào
Tuy nhiên, mình cảm giác trong HTML/CSS có một tầng nào đó mà mình sẽ mãi không hiểu nổi. Demo này đúng là như vậy: người này đang tạo ra một ô cửa kính phủ sương, còn mình thì vẫn chưa căn giữa nổi một cái
divdivnữa thường là ý hayNhìn hầu hết website hiện đại,
divđược chất thành những đống khổng lồ. Nếu muốn mộtdivđược căn giữa, thì tạo thêm mộtdivchiếm toàn bộ không gian để căn giữa bên trong nó sẽ tương đối dễ hơnNhiều thủ thuật thị giác cũng tương tự, nhưng ví dụ này rất gọn gàng nên càng ấn tượng hơn
Không hẳn là kính phủ sương, nhưng mình đã thử thêm hiệu ứng kính vào sidebar của https://www.gyan.dev/ffmpeg/builds/