Scroll snap là gì ? Tìm hiểu chuyên sâu về CSS Scroll Snap

css scroll snap

Bài viết được tham khảo và xin phép tác giả Ishadeed.

Hi! Xin chào các bạn hôm nay mình lại mang đến cho các bạn một bài viết mới khá là hay và chất lượng được tham khảo và viết lại dưới ngôn ngữ của chúng ta dựa trên bài viết gốc của tác giả Ishadeed. Trong bài viết này mình và các bạn sẽ cùng nhau tìm hiểu về CSS Scroll Snap nhé để xem thử nó là cái gì ? Và áp dụng vào thực tế ra sao nha.

Tại sao phải dùng scroll-snap ?

Chắc các bạn cũng biết nhu cầu sử dụng các thiết bị mobile, tablet ngày càng nhiều thì các trang web chúng ta phát triển việc phải có Responsive là đương nhiên, kèm theo đó là UX(trải nghiệm người dùng) trên các thiết bị đó. Ví dụ như một danh sách hình ảnh, nếu chúng ta để hiển thị chiều dọc trên điện thoại thì buộc người dùng phải scroll rất nhiều do đó phải tối ưu làm sao để người dùng có thể lướt qua xem dễ dàng hơn(scroll ngang).

Nếu các bạn code cho những giao diện dạng danh sách hình ảnh hay bài viết, thì chắc hẳn các bạn cũng có làm cho các phần tử scroll ngang với thuộc tính overflow-x: auto rồi. Ví dụ chúng ta có HTML và CSS như sau

<div class="section">
  <div class="section__item">Item 1</div>
  <div class="section__item">Item 2</div>
  <div class="section__item">Item 3</div>
  <div class="section__item">Item 4</div>
  <div class="section__item">Item 5</div>
</div>
.section {
  white-space: nowrap;
  overflow-x: auto;
}

Trước đây khi chưa có Flexbox thì white-space: nowrap thường hay được dùng để làm cho các phần tử nằm trên cùng một hàng mà không bị rớt xuống. Nhưng giờ đã có Flexbox rồi thì chúng ta sẽ cải thiện nó đơn giản hơn như này

.section {
  display: flex;
  overflow-x: auto;
}

Vấn đề scroll với overflow

Vấn đề chính ở đây là chỉ với overflow thì việc trải nghiệm người dùng vẫn chưa tốt. Chúng ta cần giải pháp khác tốt hơn để người dùng dễ dàng sử dụng và thích nó. Nếu như với cách cơ bản là dùng overflow-x: auto thì nó sẽ không được mượt mà, các bạn xem video sẽ hiểu rõ hơn

Giới thiệu CSS scroll-snap

Để sử dụng scroll-snap cho một container nào đó thì những phần tử bên trong phải là inline và rất dễ dàng để làm việc đó với CSS Flexbox mà mình đã đề cập ở trên.

<div class="section">
  <div class="section__item">Item 1</div>
  <div class="section__item">Item 2</div>
  <div class="section__item">Item 3</div>
  <div class="section__item">Item 4</div>
  <div class="section__item">Item 5</div>
</div>
.section {
  display: flex;
  overflow-x: auto;
}

Với đoạn code ở trên thì vẫn chưa được, chúng ta cần thêm 2 thuộc tính nữa thì scroll-snap nó mới có thể hoạt động được. Vậy câu hỏi đặt ra là 2 thuộc tính đó là gì và dùng chúng ở đâu và dùng như thế nào ?

Đầu tiên chúng ta cần sử dụng thuộc tính scroll-snap-type cho container bao ngoài. Trong ví dụ của chúng ta thì container chính là thẻ div có class .section. Sau đó thì chúng ta sẽ thêm một thuộc tính khác scroll-snap-align cho các phần tử con bên trong, ở đây là .section__item

.section {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}

.section__item {
  scroll-snap-align: start;
}

Mình đoán là các bạn sẽ tự hỏi là những giá trị như x mandatorystart là cái gì thế nhỉ ? Đừng lo lắng, mình sẽ giải thích kỹ càng và chi tiết cho các bạn ngay sau đây thôi. Với những thuộc tính này thì cái container của chúng ta .section lúc này scroll nó mượt hơn và tốt hơn nhiều rồi. Xem video nè

Thuộc tính Scroll snap type

Theo như CSS thì thuộc tính scroll-snap-type xác định kiểu snap cho container sử dụng scroll-snap có kiểu snap như thế nào và hướng scroll của container đó. Đọc khái niệm thì khó hiểu thật, vì mấy từ này không có dịch sang tiếng Việt của chúng ta đươc, thôi vào phân tích và code thử xem nó hoạt động như thế nào nha.

Hướng snap của container

Như khái niệm của nó thì trong thuộc tính scroll-snap-type có giá trị truyền vào là hướng mình muốn hiển thị ở đây là xy tương ứng chiều ngang và chiều dọc.

/* Chiều ngang */
.section {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x;
}

/* Chiều dọc */
.section {
  height: 250px;
  overflow-y: auto;
  scroll-snap-type: y;
}

Kiểu snap

Như ở trên thì chúng ta có thể xác định hướng của scroll snap, còn ở đây thì chúng ta có thể sử dụng kiểu mà nó được snap khi chúng ta scroll với 2 giá trị là mandatory | proximity

Giá trị mandatory nghĩa là trình duyệt phải snap theo từng điểm scroll. Giả sử thuộc tính scroll-snap-align có giá trị là start đi ha. Nghĩa là scroll lúc này phải snap theo hướng bắt đầu của container.

Các bạn thấy ở đường line màu xanh dương, là mỗi khi người dùng scroll ngang thì các phần tử luôn nằm sát về phía bên trái(đây gọi là start)

.section {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}

.section__item {
  scroll-snap-align: start;
}

Tuy nhiên, nếu giá trị là proximity, thì trình duyệt cũng vẫn hoạt động bình thường, nhưng kiểu snap của nó hơi khác chút đôi khi không có ngon lành như mandatory. Và các bạn lưu ý rằng proximity là giá trị mặc định nếu các bạn không thiết lập giá trị nhé.

.section {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x proximity;
}

Scroll Snapping Alignment

Tiêu đề mục này mình để tiếng Anh luôn vì không biết ghi ra tiếng Việt sao cho dễ hiểu, nói chung là canh vị trí snap cho phần tử con bên trong nha. Và có 3 giá trị đó là start, centerend. Để dễ hiểu hơn thì các bạn nhìn vào cái hình này cho nó trực quan hơn nà(nhìn cái hình nam châm nha)

Có nghĩa là khi dùng scroll-snap-type khi scroll ngang và các phần tử con mỗi lần scroll thì nó nằm theo kiểu canh bên trái, ở giữa hoặc là nằm cuối như hình trên nha. Ngược lại khi các bạn làm scroll dọc thì nó sẽ là trên cùng, ở giữa và dưới cùng như hình này:

Lý thuyết và hình thôi thì mình nghĩ các bạn vẫn chưa hình dung ra được đâu, đặc biệt bài này mình viết mấy từ cũng khó hiểu nữa. Coi video của từng giá trị khác nhau thì các bạn sẽ thông não hơn.

start

center

end

Sử dụng scroll-snap-stop

Đôi khi các bạn cần tìm cách để tối ưu trải nghiệm hơn, giả sử người dùng vô tình lướt quá nhanh khi scroll, điều đó sẽ làm họ bị miss vài phần tử mà họ không biết. Các bạn coi video dưới này demo vấn đề đó nè

Giá trị mặc định của thuộc tính scroll-snap-stopnormal. Nghĩa là nó cho phép người dùng lướt nhanh qua các phần tử như video demo ở trên. Để khắc phục vấn đề này thì các bạn chỉ cần thay đổi giá trị lại thành always là ngon lành cành đào.

.section__item {
  scroll-snap-align: start;
  scroll-snap-stop: always; // mặc định là normal
}

Các ví dụ thực tế

Friends List

Một ví dụ thực tế có sử dụng scroll snap là giao diện danh sách bạn bè từ Facebook như hình

.list {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  gap: 1rem;
  scroll-padding: 48px;
  padding-bottom: 32px;
  -webkit-overflow-scrolling: touch;
}

.list-item {
  scroll-snap-align: start;
}

Có một vấn đề khi sử dụng scroll snap đó chính là nếu các phần tử có box-shadow thì nó sẽ bị cắt đi, cho nên tuỳ vào thiết kế thì các bạn nên thêm padding vào các phần tử nha. Như ở giao diện Friend List này thì các bạn sẽ thấy có padding-bottom: 32px để box-shadow có thể hiển thị đẹp đó.

Avatars List

Với trường hợp này thì nếu sử dụng scroll-snap-align với giá trị là center thì sẽ đẹp hơn vì khi người dùng scroll thì thông tin sẽ được hiển thị chính giữa luôn.

.list {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}

.list-item {
  scroll-snap-align: center;
}

Lưu ý

Nếu các bạn sử dụng CSS scroll snap thì mình khuyến khích làm cho những layout dạng danh sách, người dùng lướt ngang trên các thiết bị như điện thoại, tablet, chứ đừng có dùng bừa bãi vào nội dung như dưới này là tèo ngay

.wrapper {
  scroll-snap-type: y mandatory;
}

h2 {
  scroll-snap-align: start;
}

See the Pen
Scroll Snap – Accessibility – Bad Example
by Ahmad Shadeed (@shadeed)
on CodePen.

Tạm kết

Giờ mình mới viết về bài này của tác giả Ishadeed, còn sử dụng scroll-snap này thì mình đã sử dụng lâu rồi. Lúc trước mình được giao task làm slider mượt mà trên điện thoại, mình dùng thư viện Slick Slider nhưng cảm thấy nó không được mượt và hay bị giật, ngồi mày mò và tìm được những đoạn code về CSS scroll-snap này và từ đó mình sử dụng nó thường xuyên luôn.

Mình hi vọng với bài viết này thì sẽ giúp cho các bạn biết thêm nhiều kiến thức mới hơn, từ đó biết cách áp dụng vào dự án của riêng mình nhé. Bài viết này khá là rối và sẽ có nhiều chỗ chưa tốt, mong được các bạn góp ý.

Subscribe
Notify of
guest

14 Comments
Inline Feedbacks
View all comments
Bình Văn
Bình Văn

Một thuộc tính rất hữu ích nên dùng, thanks tác giả !

Chubbie-Dev
Chubbie-Dev

Rất cảm ơn Tuấn, bài viết cực kỳ bổ ích!

Thuong
Thuong

Bài viết hay.

Akai shuichi
Akai shuichi

nhược điểm của nó là không touch được trên PC nhưng vẫn có thể fix bằng js

Max
Max
Reply to  Akai shuichi

Bạn có thể chia sẻ cách làm được không ạ. thanks bạn

Apolos
Apolos

=))) Đúng cái em cần,em cảm ơn nhiều ạ

GaFDev
GaFDev

Cảm ơn vì bài viết rất hay ạ.

Nhật Võ
Nhật Võ

Cảm ơn AD nhiều nhé. Bài viết hay, rõ ràng và rất chỉnh chu.

Hoàng
Hoàng

Anh ơi, có cách nào để trên mobile, tab active tự động được đẩy lên đầu không anh?

Huyên
Huyên

Ok

Nam
Nam

bài viết hay

Văn Hậu
Văn Hậu

Trước khi biết tính năng này qua tutorial Tailwind CSS của bạn bên Youtube, mình cũng từng phải code một cái slider bằng ES6 và CSS (transform, transition), yêu cầu phải smooth cả trên mobile và desktop. Thực sự nó quá vất vả luôn.