5 điểm bởi GN⁺ 2025-09-09 | 2 bình luận | Chia sẻ qua WhatsApp
  • Giới thiệu cách tái tạo hiệu ứng Liquid GlassApple công bố tại WWDC 2025 trên web bằng CSS, SVG và các phép tính khúc xạ dựa trên vật lý
  • Giải thích nguyên lý của hiện tượng khúc xạ và quá trình mô phỏng khúc xạ, mô tả bề mặt kính bằng định luật Snell
  • Sử dụng SVG displacement map để tạo trường vector dịch chuyển phù hợp cho render và trình diễn khả năng áp dụng vào các UI component thực tế
  • Trên Chrome, có thể dùng SVG filter làm backdrop-filter, đồng thời đưa ra ví dụ áp dụng cho nhiều thành phần UI khác nhau như kính lúp, công tắc, trình phát nhạc
  • Có thể triển khai hiệu ứng theo thời gian thực, nhưng vẫn tồn tại vấn đề tương thích đa trình duyệt và giới hạn hiệu năng; bài viết cũng đề cập kế hoạch open source trong tương lai

Giới thiệu

Apple đã lần đầu giới thiệu hiệu ứng Liquid Glass tại WWDC tháng 6 năm 2025. Hiệu ứng này khiến các phần tử giao diện trông giống như kính khúc xạ có bề mặt cong, mang lại trải nghiệm thị giác tương tự bề mặt kính thật. Bài viết này trình bày cách thực hành tạo hiệu ứng tương tự trong môi trường web bằng CSS, SVG displacement map và các phép tính khúc xạ dựa trên vật lý. Mục tiêu không phải là một bản triển khai hoàn chỉnh, mà là một proof of concept có thể mở rộng nhằm tái tạo các đặc trưng chính như khúc xạ và highlight phản xạ. Bài viết bắt đầu từ nguyên lý cơ bản về cách ánh sáng khúc xạ khi đi qua các vật liệu khác nhau, rồi xây dựng hiệu ứng từng bước. Demo tương tác được cung cấp ở cuối hiện chỉ hoạt động đúng trên Chrome.

Tìm hiểu hiện tượng khúc xạ

Khúc xạ là hiện tượng hướng truyền của ánh sáng thay đổi khi nó đi từ vật liệu này sang vật liệu khác. Điều này xảy ra do tốc độ ánh sáng khác nhau trong mỗi môi trường, và mối quan hệ giữa góc tới với góc khúc xạ được biểu diễn bằng định luật Snell:

  • n1 * sin(θ1) = n2 * sin(θ2)
    • n1: chiết suất của môi trường thứ nhất
    • θ1: góc tới
    • n2: chiết suất của môi trường thứ hai
    • θ2: góc khúc xạ

Có thể quan sát trong sơ đồ tương tác:

  • Nếu chiết suất của hai môi trường bằng nhau, ánh sáng đi thẳng mà không khúc xạ
  • Nếu môi trường thứ hai có chiết suất cao hơn, ánh sáng bị bẻ về phía pháp tuyến
  • Nếu môi trường thứ hai có chiết suất thấp hơn, ánh sáng lệch ra xa pháp tuyến; trong một số trường hợp có thể xảy ra phản xạ toàn phần bên trong
  • Nếu tia tới vuông góc với bề mặt, nó vẫn đi thẳng bất kể chiết suất

Giới hạn của dự án này

Để giới hạn độ phức tạp và đơn giản hóa thuật toán, bài viết đặt ra các điều kiện sau:

  • Chiết suất của môi trường bên ngoài là 1 (không khí)
  • Vật liệu kính bên trong dùng giá trị 1.5 (kính thông thường)
  • Chỉ xét một lần khúc xạ duy nhất (bỏ qua khúc xạ tại điểm thoát ra)
  • Tia tới luôn vuông góc với mặt nền phía sau
  • Mọi đối tượng đều là hình 2D và chỉ dùng dạng tròn (có thể mở rộng sang hình chữ nhật v.v. nhưng cần thêm tính toán)
  • Không có khoảng hở giữa đối tượng và mặt nền
  • Với các điều kiện này, có thể dùng định luật Snell để tính đơn giản mọi tia sáng
Quảng cáo

Tạo bề mặt kính

Để triển khai hiệu ứng Liquid Glass, cần định nghĩa bằng toán học mặt cắt của kính ảo (thấu kính hoặc panel cong).

Hàm bề mặt

Bề mặt kính được định nghĩa bằng surface function, biểu diễn độ dày từ mép vào đến phần trong phẳng

  • Giá trị đầu vào của hàm: 0 là mép ngoài, 1 là cuối bezel (điểm bắt đầu mặt phẳng)
  • Từ đạo hàm tại độ dày của từng điểm, lấy được vector pháp tuyến của bề mặt
const height = f(distanceFromSide);
const delta = 0.001;
const y1 = f(distanceFromSide - delta);
const y2 = f(distanceFromSide + delta);
const derivative = (y2 - y1) / (2 * delta);
const normal = { x: -derivative, y: 1 };

Các loại hàm bề mặt chính

  • Convex Circle: y = sqrt((1 - (1 - x))^2)
    • Dạng cung tròn đơn giản, càng vào trong càng nhanh chóng phẳng ra nên mép khúc xạ hiện rõ
  • Convex Squircle: y = ((1 - (1 - x))^4)^(1/4)
    • Hình dạng Apple thường ưa dùng, ranh giới giữa phần cong và phần phẳng mượt hơn nên khi mở rộng vẫn cho hiệu ứng tự nhiên
  • Concave: y = 1 - Convex(x)
    • Dạng lõm (ngược với lồi), ánh sáng bị khúc xạ ra ngoài biên đối tượng nên cần lấy mẫu ở bên ngoài
  • Lip: y = mix(Convex(x), Concave(x), Smootherstep(x))
    • Cấu trúc kết hợp với phần mép nhô lên và một độ lõm nhẹ ở trung tâm
Quảng cáo

Chỉ với bốn hàm này cũng có thể so sánh khá hiệu quả sự khác biệt khúc xạ theo từng hình dạng bề mặt.

Mô phỏng

Dựa trên từng hàm bề mặt, bài viết mô phỏng đường đi khúc xạ của tia sáng để trực quan hóa sự khác biệt của hiệu ứng thực tế.

  • Dạng lồi (Convex) gom đường đi ánh sáng vào trong, còn dạng lõm (Concave) đẩy chúng ra ngoài
  • Liquid Glass của Apple phần lớn ưu tiên dạng lồi (ngoại lệ như Switch)
  • Mũi tên nền hiển thị lượng khúc xạ (độ dịch chuyển) bằng màu theo độ lớn
  • Ở cùng khoảng cách tính từ biên trái/phải sẽ có cùng độ dịch chuyển, nên có thể tái sử dụng hiệu quả

Tạo trường vector dịch chuyển

Xây dựng một trường vector biểu diễn hướng và độ lớn dịch chuyển của ánh sáng tại từng vị trí trên toàn bộ bề mặt kính

  • Với hình tròn, chuyển động luôn theo hướng pháp tuyến dựa trên đường biên

Tính trước độ lớn dịch chuyển

  • Do độ lớn dịch chuyển đối xứng theo khoảng cách từ biên, có thể tính trước các giá trị theo đơn vị bán kính rồi lưu vào mảng
  • Trong 2D chỉ cần tính một lần (mô phỏng 127 tia) rồi quay quanh trục z để tạo toàn bộ trường

Chuẩn hóa vector

Để dùng vector trong displacement map, cần chuẩn hóa (scale tối đa 1.0)

  • Lấy giá trị dịch chuyển lớn nhất làm chuẩn rồi chia độ lớn của các vector còn lại cho giá trị này
const maximumDisplacement = Math.max(...displacementMagnitudes);
displacementVector_normalized = {
  angle: normalAtBorder,
  magnitude: magnitude / maximumDisplacement,
};

Khi chuyển đổi sang đơn vị pixel thực tế trong SVG displacement map, giá trị lớn nhất ban đầu sẽ được khôi phục bằng cách nhân lại qua scale.

Quảng cáo

SVG Displacement Map

Để áp dụng kết quả tính toán khúc xạ vào render trong trình duyệt một cách thực tế, bài viết sử dụng SVG displacement map

  • Mỗi kênh (RGBA, 8-bit) của <feDisplacementMap /> có thể lần lượt đảm nhiệm độ dịch chuyển theo trục X, Y
  • Mỗi kênh có giá trị từ 0 đến 255, trong đó 128 là trạng thái trung tính (không dịch chuyển)
  • displacement map bắt buộc phải được chuyển thành ảnh
<svg colorInterpolationFilters="sRGB">
  <filter id={id}>
    <feImage
      href={displacementMapDataUrl}
      x={0}
      y={0}
      width={width}
      height={height}
      result="displacement_map"
    />
    <feDisplacementMap
      in="SourceGraphic"
      in2="displacement_map"
      scale={scale}
      xChannelSelector="R"
      yChannelSelector="G"
    />
  </filter>
</svg>

Scale

Giá trị của kênh Red(X) và Green(Y) được ánh xạ vào khoảng [−1, 1]

  • Sau đó nhân với độ dịch chuyển pixel tối đa thông qua thuộc tính scale để tạo render thực tế
  • Có thể animate scale để điều chỉnh cường độ hiệu ứng

Chuyển vector → giá trị Red/Green

  • Chuyển vector dịch chuyển (góc, độ lớn) sang tọa độ trực giao x, y rồi ánh xạ về 0~255 với mốc 128 là trung tính
const x = Math.cos(angle) * magnitude;
const y = Math.sin(angle) * magnitude;
const result = {
  r: 128 + x * 127,
  g: 128 + y * 127,
  b: 128,
  a: 255,
};

Ảnh hoàn chỉnh sau đó có thể được dùng làm displacement map cho SVG filter.

Playground

Trong Playground tương tác, người dùng có thể thay đổi theo thời gian thực hình dạng bề mặt, độ dày bezel, độ dày kính, effect scale v.v. để trải nghiệm sự thay đổi của trường khúc xạ, displacement map và kết quả render cuối cùng.

Quảng cáo

Specular Highlight

Cuối cùng, bài viết thêm specular highlight (highlight sáng ở mép bề mặt kính)

  • Cách triển khai của Apple là kiểu rim light, trong đó cường độ sáng thay đổi theo pháp tuyến bề mặt và góc của nguồn sáng

Kết hợp khúc xạ và Specular Highlight

Trong SVG filter cuối cùng, displacement map và ảnh specular highlight được nạp riêng bằng <feImage /> rồi gộp lại bằng <feBlend /> để tạo hiệu ứng hoàn chỉnh

  • Có thể tinh chỉnh các tham số filter để tạo nhiều phong cách thị giác khác nhau

Dùng SVG filter làm backdrop-filter

  • Để thực sự áp dụng hiệu ứng Liquid Glass lên UI component, cần có hỗ trợ backdrop-filter: url(#...) của Chrome
  • Vì kích thước ảnh của backdrop-filter không tự động khớp, nên bắt buộc phải chuẩn bị displacement map tương ứng với kích thước phần tử
.glass-panel {
  backdrop-filter: url(#liquidGlassFilterId);
}

Áp dụng lên UI component thực tế

Bài viết còn triển khai ví dụ áp dụng vào các UI component thực tế dựa trên refraction và displacement map đã tính toán

  • Chỉ Chrome mới có thể xử lý SVG filter dưới dạng backdrop-filter
  • Các ví dụ không phải component production thực thụ, mà nhằm trình diễn cách hiệu ứng Liquid Glass có thể được áp dụng lên nhiều loại UI khác nhau

Magnifying Glass

  • Dùng refraction và zoom ở cả hai phía cùng với hai displacement map
  • Bổ sung bóng đổ và điều chỉnh scale để tạo hiệu ứng tương tác
  • Có thể kéo để biến dạng thấu kính và quan sát đường khúc xạ
  • Thêm specular highlight mượt mà
Quảng cáo

Searchbox

  • Áp dụng hiệu ứng Liquid Glass cho dạng ô nhập liệu tiêu chuẩn

Switch

  • Dùng lip bezel để phần ngoài là lồi, phần trong là lõm
  • Chỉ thanh trượt ở giữa được phóng to/thu nhỏ, còn phần mép thì áp dụng khúc xạ ảnh bên trong

Slider

  • Dùng convex bezel, hiển thị nguyên giá trị hiện tại qua lớp kính, còn hai bên thì áp dụng khúc xạ nền

Music Player

  • Mô phỏng phong cách panel Liquid Glass của Apple Music

  • Dùng convex bezel và specular highlight nhẹ để tăng cảm giác khối

  • Sử dụng iTunes Search API để tải album art, tên bài hát và các thông tin khác

  • (Cung cấp danh sách tên bài hát và thông tin album dưới dạng danh sách)

Kết luận

Prototype này diễn giải đơn giản khái niệm Liquid Glass của Apple bằng hiệu ứng khúc xạ theo thời gian thực và highlight cơ bản. Nó chỉ thực sự khả dụng trên trình duyệt nền tảng Chromium (hoặc Electron), còn ở các trình duyệt khác có thể thay bằng lớp blur.
Đây là một bản triển khai mang tính thử nghiệm; việc phải tái tạo displacement map mỗi khi thay đổi shape/size là cực kỳ kém hiệu quả (chỉ một số tham số như scale của filter mới có thể animate).
Tác giả cho biết đang cân nhắc phát hành open source trong tương lai, đồng thời bày tỏ sự quan tâm tới tối ưu hóa và dọn dẹp mã nguồn.

2 bình luận

 
bobross0 2025-09-16

Có lẽ đây là bản giống nhất với Liquid Glass mà tôi từng thấy trên web.

 
GN⁺ 2025-09-09
Ý kiến Hacker News
  • Từng có trải nghiệm làm tính năng tương tự bằng WebGL shader, có ưu điểm là chạy được trên nhiều trình duyệt, chia sẻ https://real-glass.vercel.app, phần khó nhất là tái hiện chính xác hiệu ứng khúc xạ phía sau các phần tử HTML thực tế
    • Tò mò không biết nguyên nhân nào gây ra hiện tượng bóng mờ/độ trễ khi đặt hiệu ứng kính lên trên văn bản rồi di chuyển
    • Thấy quá đẹp, trông như còn tái hiện cả hiệu ứng tán sắc khiến màu bị tách ra ở các cạnh
    • Hình ảnh thì đẹp nhưng để dùng thực tế thì phản hồi quá chậm, bản của tác giả gốc chạy mượt hơn nhiều
    • Ấn tượng thật
  • Khá ấn tượng khi cứ cuộn trang là ngay cả trên M4-Max Macbook Pro cũng bị khựng, nếu công nghệ kiểu này được áp dụng cho toàn bộ UI thì khá lo về mặt hiệu năng, có lẽ Apple làm được là nhờ tối ưu ở mức cực đoan
    • Với tư cách người viết bài, tôi đã định sửa trước các vấn đề hiệu năng nhưng ai đó đã đăng lên HN sớm hơn dự kiến, nhận xét đó là đúng nên hiện tại nó hơi chậm và cần tối ưu thêm, không chỉ bản đồ khúc xạ/độ dịch mà cả các phần khác như trực quan hóa cũng vẫn chưa được tối ưu
    • Vì đã nhanh chóng cải thiện hiệu năng trên Chrome nên chắc giờ đã khá hơn một chút, còn trên Safari thì việc render SVG vẫn chậm, do bị đăng ngoài dự kiến nên vẫn còn chỗ cần cải thiện thêm
    • Trang này cuộn không mượt, trong đa số trường hợp CSS không tận dụng GPU tốt, có vẻ Apple đã thêm xử lý chuyên biệt ở silicon để phục vụ việc xử lý UI
    • Máy tôi cũng như vậy, ngay cả hiệu ứng viền cũng không hiện đúng
  • Nội dung hay, nhưng cách tổ chức và chất lượng tổng thể của cả bài viết cũng rất xuất sắc, bản thân khái niệm Liquid glass không thật sự mang lại lợi ích UX bổ sung rõ rệt nào cả (thậm chí nếu lạm dụng còn có thể làm hại UX), nhưng đây là một trải nghiệm mới mẻ và thú vị
  • Tác giả nhấn mạnh đây là demo chỉ dành cho Chrome, và demo tương tác cuối cùng chỉ chạy trên Chrome (do giới hạn của backdrop-filter khi dùng SVG filter), còn trên trình duyệt khác vẫn có thể đọc bài hoặc xem mô phỏng đơn giản. Về điều này có một phản ứng đùa là: "Thật ô nhục cho cả gia đình anh!"
    • Việc làm theo cách này là điều khó tránh, mục đích là để cho thấy tính năng đó chỉ được hỗ trợ trên một số trình duyệt nhất định
    • Buồn cười là trong trường hợp của tôi, trên Chrome trang lại chậm hơn và cuộn giật hơn, trong khi trên Firefox dù hiệu ứng đó không được hỗ trợ thì lại mượt hơn, dù vậy tôi vẫn rất ấn tượng với bản thân bài viết
    • Tôi cũng có phản ứng tương tự, nhưng kỳ lạ là trên FireFox nó vẫn trông khá ổn
    • Nếu tò mò về tham chiếu, có thể xem https://youtu.be/GamP4chXJ2I?t=17
  • Việc ngôn ngữ thiết kế liquid glass được áp dụng lên web là điều sớm muộn cũng xảy ra, nhưng nếu một website làm hao pin của tôi chỉ vì bóp méo văn bản thì tôi sẽ không ở lại lâu, nhiều người đã chỉ ra hiện tượng giật lag nên tôi không nhắc thêm nữa
  • Đây là một tác phẩm đẹp và cho thấy rất nhiều công sức, nhưng liquid glass là cả một ngôn ngữ thiết kế, gồm những thứ như các phần tử gần nhau hợp nhất kiểu metaball, nhiều chế độ tint/clear khác nhau, và các control nằm trên lớp tách biệt với nội dung; vì vậy bản triển khai này nói đúng hơn chỉ gần với một "glass shader" đơn thuần
    • Việc hợp nhất phần tử có thể giải quyết bằng bộ lọc đơn giản hơn nhiều là bộ lọc "Goo", đây là cách đã dùng từ lâu, triển khai tham khảo: https://codepen.io/lenymo/pen/pJzWVy
  • Đã fork thư viện JS cho liquid-glass và thêm bản vá sửa vị trí, dùng khi thuyết trình sẽ khá vui, mã nguồn: https://github.com/nkzw-tech/liquid-glass
    • Tuyệt thật, thậm chí tôi còn thích bản này hơn
  • Trên Firefox chỉ một phần hiệu ứng hoạt động (đổi lại có hiệu năng!), nhưng đây là bản triển khai tốt nhất tôi từng thấy cho đến nay, càng ấn tượng hơn vì mấy ngày gần đây tôi đã nghiên cứu khá nhiều về chủ đề này, điều tôi thích nhất là thiết kế website và các phần trực quan tương tác được chăm chút kỹ lưỡng, cảm giác ngang tầm tác phẩm của Bartosz Ciechanowski và Josh Comeau, mong mã nguồn sẽ được công khai
  • Dù có giới hạn về hỗ trợ trình duyệt, tôi vẫn thấy đây là một nỗ lực rất đáng khen, các ví dụ tương tác chèn ngay trong bài mang lại giá trị bổ sung, có lúc tạo cảm giác như đang đọc một bài của Ciechanowski (tham khảo: https://ciechanow.ski/)
  • Tôi tự hỏi liệu scrollbar và button ray-traced mới này có thực sự hữu ích hơn và giúp tăng năng suất so với kiểu Turbo Vision chế độ văn bản ngày xưa hay các nút của Windows 3 hay không