3 điểm bởi GN⁺ 2023-08-06 | 3 bình luận | Chia sẻ qua WhatsApp
  • Khi số lượng nền tảng mạng xã hội mới, client, ứng dụng và các bản port web dựa trên React Native tăng lên, ngày càng có nhiều trường hợp website đánh mất hành vi web cơ bản mà người dùng mong đợi
  • Các nguyên nhân chính được nhắc đến gồm áp lực ra mắt nhanh, thiếu kỹ sư UI, thiết kế ưu tiên cảm ứng trên di động, và các cách triển khai dùng JavaScript để thay thế hành vi mặc định của trình duyệt
  • Các tính năng mặc định của trình duyệt như sao chép văn bản, nhấp chuột phải vào liên kết và ctrl + click, phóng to trình duyệt, bố cục responsive, :hover:focus, cập nhật URL·lịch sử, thanh cuộn, ctrl + f cần phải tiếp tục hoạt động như bình thường
  • Ở các thẻ có thể nhấp, việc bỏ pointer-events hoặc chồng nhiều lớp lên nhau, hay triển khai điều hướng bằng divon-click thay vì anchor, đều phá vỡ trải nghiệm liên kết thông thường
  • Dù có nhiều điểm chồng lấp với vi phạm accessibility, web app vẫn nên duy trì những tính năng web bình thường mà người dùng mong đợi, thay vì cố trông giống ứng dụng di động

Những hành vi cơ bản mà website đã đánh mất

  • Ngày càng có nhiều dự án web chặn mất những tính năng web bình thường mà người dùng mong đợi
  • Khi các nền tảng mạng xã hội mới tăng lên, nhiều client và ứng dụng cũng được tạo ra, và cũng có không ít trường hợp cố gắng chia sẻ mã giữa các nền tảng như React Native
  • Bản thân những nỗ lực đó là tích cực, nhưng không chỉ các yêu cầu accessibility cơ bản như văn bản alt cho ảnh bị bỏ sót, mà cả cách tương tác thông thường của web cũng bị mất theo
  • Có thể thấy các nguyên nhân sau
    • Áp lực phải phát hành thật nhanh đến mức có thể kiểm thử được
    • Dự án không có kỹ sư UI
    • Thiết kế ưu tiên nhập liệu bằng cảm ứng trên di động và bỏ qua các phương thức nhập hay thiết bị khác
    • Cách triển khai lách qua hoặc thay thế hành vi mặc định của trình duyệt bằng JavaScript

Những tính năng web bình thường cần được giữ lại

  • Sao chép văn bản phải hoạt động được
    • Trong các component thẻ có thể nhấp, nếu bỏ pointer-events hoặc chồng lớp vùng có thể nhấp, việc chọn và sao chép văn bản có thể bị chặn
  • Các phần tử điều hướng như liên kết phải giữ nguyên chức năng liên kết
    • Cần có thể mở menu ngữ cảnh bằng nhấp chuột phải để sao chép văn bản hoặc địa chỉ liên kết
    • Các phím tắt liên kết thông thường như ctrl + click trên Windows để mở trong tab mới phải hoạt động
    • Nên dùng phần tử anchor thay vì gắn on-click vào div để điều hướng
  • Khi phóng to trình duyệt, bố cục không được vỡ, và người dùng phải có thể phóng to để đọc
  • Web responsive không nên vừa dưới 1200px là rơi ngay về một bố cục di động đơn giản; ngay cả ở viewport hẹp cũng cần tận dụng không gian hợp lý
    • Mastodon và Twitter có thể xem là ví dụ về việc khi thu hẹp chiều rộng trình duyệt, UI vẫn giữ được cảm giác quen thuộc và nhìn chung tận dụng không gian khá tốt
  • Web app cần cung cấp đúng các trạng thái tương tác như :hover, :focus, :active
    • Ở một số trường hợp port ứng dụng React Native sang web, có khi không có style :hover hoặc :focus, hoặc xuất hiện style :active trông kỳ lạ như bị vô hiệu hóa
  • Nếu sau khi nhấp mà UI thay đổi hoàn toàn như sang một trang mới, thì lịch sử trình duyệt và URL cũng phải thay đổi theo
    • Nếu không thể liên kết đến một trạng thái UI trông như một trang độc lập, và trạng thái biến mất sau khi điều hướng, khả năng sử dụng sẽ giảm
  • Không nên ẩn thanh cuộn
    • Người dùng có thể muốn nhấp và kéo thanh cuộn
  • Không nên chặn các phím tắt trình duyệt thông thường để thay bằng chức năng nội bộ của ứng dụng
    • Nếu làm cho ctrl + f mở ô tìm kiếm tùy biến trong app, chức năng tìm kiếm trên trang có thể không hoạt động như bình thường
  • Dù có nhiều phần trùng với các mục có thể bị xem là vi phạm accessibility, trọng tâm ở đây là làm sao để web app không phá vỡ kỳ vọng cơ bản về trình duyệt của người dùng
  • Có thể tiếp tục bàn về các ví dụ bị thiếu trên Mastodon

3 bình luận

 
plastic041 2023-08-06

Có vẻ nội dung bài viết bị nhầm.

 
xguru 2023-08-07

Ồ, thú vị thật. Có vẻ như việc crawl chính bài viết trên blog đó đang diễn ra hơi bất thường. Có lẽ phải xem lại phần crawler một lần.

 
GN⁺ 2023-08-06
Ý kiến trên Hacker News
  • Nếu học web bằng React trước rồi mới học HTML sau, sẽ có chuyện bạn không còn để ý đến hành vi mặc định của liên kết
    Khi tôi gia nhập nhóm, mọi liên kết đều là nút bấm, phần tử tùy ý hoặc được xử lý bằng onClick; không ai phàn nàn, nhưng Ctrl+click trở nên vô dụng và menu chuột phải cũng không đưa ra các tùy chọn như mong đợi
    Riêng về liên kết thì tôi nghĩ không có gì để thương lượng

    • Tôi thật sự ghét kiểu lạm dụng JS này; nó đang ngày càng phá hỏng thêm nhiều thứ lẽ ra phải được làm đúng cách
      Ngay cả archbee, một nền tảng tài liệu được YC đầu tư, cũng không thể mở kết quả tìm kiếm trong tab mới, nên bạn phải mở một kết quả trong tab hiện tại, nếu không đúng thì quay lại, tìm kiếm lại rồi mở kết quả tiếp theo
      Có thể xem ví dụ ở đây: https://docs.sparklayer.io/
    • Phiên bản web Reddit mới biến mọi liên kết thành nút bấm nên không thể mở trong tab mới
      Thật kỳ lạ và phát điên khi một dịch vụ Internet lớn như vậy lại có vấn đề truy cập rõ ràng đến thế
    • Khoảng một nửa lý do tôi dùng nitter thay cho Twitter là vì chuyện này
      Cũng có lý do là không cần tài khoản, nhưng bạn có thể nhấp chuột phải vào chuỗi tweet để mở trong tab mới
      Với đặc thù hội thoại trên Twitter, tôi muốn mở nhiều chuỗi mới để xem trong khi vẫn giữ nguyên vị trí trên trang gốc, nhưng UI Twitter thật sự khiến việc này rất khó
    • Vấn đề liên kết là một ngọn đồi đáng để cố thủ đến cùng bất cứ lúc nào
      Không có nhiều thứ gây khó chịu hơn chuyện này; nếu phải chọn thì chắc chỉ có việc làm hỏng lịch sử duyệt web của trình duyệt
    • Trên các trang có màn hình danh sách và màn hình chi tiết, việc không thể nhấp chuột phải vào một mục hoặc dùng tiện ích mở rộng để mở màn hình chi tiết trong tab mới là thảm họa khi dùng web
      Nếu nút quay lại hoạt động tức thì và mượt mà thì còn có thể tha thứ, nhưng thực tế là bạn phải chờ nội dung tải lại và còn mất cả vị trí cuộn
      Tệ hơn nữa là có những trang như Facebook ép trạng thái popup chat giống nhau trên nhiều tab. Đóng ở một tab thì tab khác cũng đóng theo, trong khi việc mở nhiều tab là có lý do riêng
  • Ngay khoảnh khắc bạn can thiệp vào hành vi có sẵn, tôi cho rằng bạn cũng gánh luôn trách nhiệm đối với nó
    “Tính năng” bạn tạo ra không chỉ nằm trong phạm vi hẹp mà người thiết kế dự định, mà trở thành toàn bộ trải nghiệm thực tế của khách truy cập
    Nếu thay đổi logic của nút quay lại, tức là bạn đang thay đổi chính ý nghĩa mà thao tác quay lại mang lại trên trang đó, và bạn cũng phải chịu trách nhiệm khi kết quả là người dùng bối rối, tức giận chửi đó là “trang bị hỏng”
    Cần nghĩ xem bạn có thật sự sẵn sàng chịu trách nhiệm cả với những hành vi khác nhau giữa từng trình duyệt và hệ điều hành, như thanh cuộn, hay không
    Rốt cuộc, điều đó chẳng khác nào khiến website nói một thứ ngôn ngữ creole, nên cũng không có gì lạ nếu khách truy cập không hiểu ngôn ngữ đó hoặc “diễn giải sai”
    Những tính năng kiểu này không chỉ nên tránh vì muốn tử tế với khách truy cập; lợi ích thu được có vẻ hữu hạn, còn thiệt hại thì gần như vô hạn

    • Đúng vậy. Website đang hưởng lợi từ các thành ngữ thiết kế đã được tinh chỉnh trong thời gian dài
      Những trang phớt lờ các thành ngữ này trở nên khó dùng hơn vì chúng không nói thứ ngôn ngữ mà người dùng đã quen
      Cũng có một bài viết dài về sự mất mát của các thành ngữ thiết kế: https://loeber.substack.com/p/4-bring-back-idiomatic-design
  • Tôi xem đây là việc biến website thành ứng dụng, và đã đến lúc phải dừng lại
    Website nên quay lại với server-side rendering và chỉ thêm JavaScript ở mức cần thiết
    Ngược lại, web app có thể xử lý UX nhiều hơn một chút nếu điều đó có giá trị với người dùng, nhưng chừng nào còn nằm trong trình duyệt thì các nguyên tắc cơ bản vẫn được áp dụng
    Tôi ủng hộ web app vì đó là nền tảng phát triển mà ai cũng có thể tiếp cận bên ngoài hàng rào của các app store, nhưng cần ngừng đối xử với mọi website như ứng dụng
    Nếu một trang muốn xuất hiện trong kết quả công cụ tìm kiếm, thì đó là website chứ không phải web app

    • Sẽ thật tốt nếu trình duyệt có thể gửi Accept: text/markdown cho tài liệu thô, nhưng tôi nghĩ từ khoảnh khắc CSS xuất hiện thì con tàu đó đã rời bến rồi
    • Có thể bạn sẽ thích bài này: https://notan.app/
    • Tôi đồng ý với câu “website nên quay lại với server-side rendering và một chút JS”
      May là nhờ những thứ như React Server Components, có vẻ chúng ta đang quay lại hướng thêm JavaScript từng chút một vào website, nên tôi thấy mừng
    • Một web app tốt cũng có thể là website
      Đây là vấn đề có thể giải quyết nếu dành đủ thời gian
  • Tôi không hiểu vì sao các website ngân hàng lại chặn dán
    Đến lúc nhận ra là không thể dán thì mình đã sao chép văn bản xong rồi
    Nhập tay thì dễ sai hơn, còn nếu clipboard đã bị nhiễm bẩn thì khi nhận ra lệnh dán bị cấm, việc sao chép cũng đã hoàn tất rồi

    • Có cảm giác như ở đâu đó kiểu “Nhập môn lập trình form” có đoạn mã chặn sao chép và dán, rồi ý tưởng đó để lại hàng nghìn hậu duệ trên khắp web
      Dường như người ta tưởng tượng đó là một biện pháp bảo mật và tự nguyện sao chép theo
      Ngay từ đầu tôi đã không hiểu lý do chặn người dùng dán là gì
    • Trang ngân hàng của tôi không chỉ chặn dán “mật khẩu” mà còn chặn cả nhập bằng bàn phím
      “Mật khẩu” đó chỉ là 6 chữ số, và tôi còn không được tự đặt. Như thể 6 chữ số an toàn hơn hẳn chuỗi ngẫu nhiên 16 ký tự do trình quản lý mật khẩu tạo ra
      Trang bắt nhập bằng các nút ở vị trí ngẫu nhiên trong trang, nhưng nếu thiết bị đã bị nhiễm đến mức phím gõ và cú nhấp bị ghi lại, thì có lẽ kẻ tấn công cũng có thể đọc thẳng mật khẩu từ bộ nhớ trình duyệt
    • Vài ngày trước tôi đăng ký ISP mới, ô nhập mật khẩu chặn dán nên trình quản lý mật khẩu bị hỏng
      Xét từ góc độ bảo mật, đó là một quyết định tệ đến khó tin
    • Thường thì chuyện này bắt đầu khi công ty gặp vấn đề về lưu lượng bot
      Họ thử đủ cách để gây khó cho bot, rồi một ngày nọ các lập trình viên bị quản lý cấp trung thúc ép chặn sao chép–dán trên trang đăng nhập, và bot tạm dừng lại
      Vài ngày sau bot vượt qua, nhưng “bản sửa” trước đó vẫn được giữ lại với suy nghĩ “có thể chặn được một số bot”
      Thế là khoảng hơn 10 dòng JavaScript đó sống sót đến tận bản rewrite v6, rồi sau khi làm lại từ đầu vài tháng hoặc vài năm, lệnh cấm tương tự lại được đưa vào
      Tuyệt đối không phải nói từ kinh nghiệm đâu
    • Tôi không khẳng định đây là trường hợp đó, nhưng đúng là từng có malware clipboard thay nội dung đã sao chép thành địa chỉ của nó nếu nội dung trông giống địa chỉ bitcoin
      https://techcrunch.com/2018/07/03/new-malware-highjacks-your...
      Có thể họ đã nghĩ đến loại đó
  • Tôi bực khi các lập trình viên JS hào nhoáng giấu sự phức tạp và tính năng không ai yêu cầu phía sau menu select trông như HTML native
    Tôi hay gặp ở phần nhập thành phố và bang: thành phố là ô nhập văn bản, còn bang là menu thả xuống/select
    Vì là người Texas, tôi thường nhập thành phố, nhấn Tab tới menu chọn bang rồi nhấn t, t để chuyển sang phần tử form tiếp theo
    Nhưng dạo này đó lại là ô tìm kiếm văn bản được trang trí như dropdown, nên t, t không chọn Tennessee rồi đến Texas mà trở thành tìm kiếm đúng chuỗi tt
    Nó chỉ hoạt động đúng như kỳ vọng với người dùng chuột bấm vào hình tam giác rồi cuộn danh sách bang
    Nếu chưa hỏng thì đừng sửa

    • Đây phần lớn là vấn đề do lỗ hổng của nền tảng web
      Trong lịch sử, <select> thật rất khó hoặc không thể thay đổi style hay mở rộng hành vi, nên nhiều ứng dụng tự triển khai lại và thường làm rất tệ
      Có vẻ các lựa chọn thay thế tích hợp sẵn có thể style được đang xuất hiện
      Ngoài ra, vì việc chia sẻ mã giữa ứng dụng, framework và công ty rất khó, nên chỉ các công ty lớn mới có thể tạo ra những thành phần thay thế tích hợp sẵn đầy đủ tính năng, khả năng truy cập và khả năng tùy biến
      Web Components có thể giải quyết vấn đề này bằng cách cho phép cộng tác toàn cầu trên các thành phần đầu cuối phổ biến như <select>
      Bài liên quan: https://blogs.windows.com/msedgedev/2022/05/05/styling-selec...
  • Tôi cho rằng khá nhiều hành vi liên kết bị hỏng là do thiếu phương thức cấp cao để ghi đè hành vi liên kết mặc định
    Ví dụ, nếu muốn mở liên kết trong modal, tôi không muốn gắn listener sự kiện click. Sự kiện click quá thấp cấp, khiến tôi phải tự kiểm tra các phím bổ trợ
    Điều tôi thật sự muốn là nói với trình duyệt: “nếu URL cửa sổ hiện tại sắp thay đổi vì phần tử anchor này, hãy gọi hàm này thay vào đó”
    Khi đó người dùng vẫn có thể tự do mở liên kết trong cửa sổ mới hoặc tab mới, và trong trường hợp đó mã của tôi sẽ không chạy
    CSS cũng tương tự: tôi không muốn chỉ định ảnh con trỏ cho mọi phần tử và pseudo-class. Tôi muốn nói “ở những nơi định dùng con trỏ tay/chờ/thay đổi kích thước mặc định, hãy dùng ảnh tùy chỉnh này”
    Như vậy, kể cả khi có phần tử hoặc UI mới, mã vẫn an toàn cho tương lai
    Có vẻ đôi khi một số API trình duyệt cũng mắc vấn đề XY

    • Điều này khá khả thi bằng JavaScript
      Chỉ cần đăng ký onclick trên thẻ và hủy hành vi điều hướng mặc định trong event handler
      Nếu người dùng tắt JavaScript thì site vẫn hoạt động tốt, còn các hành vi trình duyệt tích hợp như menu liên kết khi nhấp phải hay Ctrl+click vẫn hoạt động nguyên vẹn
      Tuy nhiên đó là một “mẹo” khá obscure, nên sẽ tốt hơn nếu DOM API làm việc này dễ hơn
    • https://developer.mozilla.org/en-US/docs/Web/API/Navigation_...
      Tôi nghĩ đây là use case của Navigation API
    • Cuối cùng tôi cũng thấy ý nghĩ của mình trên mạng
      Thứ cần có không phải sự kiện click hay pointer, mà là một sự kiện visit cấp cao hơn
  • Khi lần đầu xem Flutter Gallery, tôi ngạc nhiên vì cảm giác như mọi thứ trong trình duyệt web đều bị hỏng: https://gallery.flutter.dev
    Tôi nhớ đặc biệt là ví dụ Reply
    Ctrl+click hay nút chuột giữa trên liên kết không hoạt động, nhấp phải cũng không, chọn và sao chép văn bản cũng không, do cấu trúc kỹ thuật nên không thể inspect element, và thử phóng to trang cũng chẳng có gì xảy ra
    Nhớ lại trải nghiệm đó cùng với một số triển khai SPA làm bằng công nghệ truyền thống hơn, tôi thấy bài viết này nói có lý

    • Flutter là một ngõ cụt nữa trên con đường tiến tới framework phát triển hợp nhất
      Dù là web hay mobile, chưa demo Flutter nào thuyết phục được tôi rằng nó có UX dùng được
    • Có vẻ nó cũng xử lý việc chọn văn bản trên trình duyệt di động một cách kỳ quặc
      Nếu lời hứa của Flutter là giống nhau ở mọi nơi, thì demo này hẳn cũng tệ như vậy trên desktop
  • Cũng mong đừng ghi đè hành vi cuộn
    Đừng cố “cải thiện” để làm thao tác cuộn “mượt hơn”
    Trên Windows có thể trông ổn, nhưng trên Mac, khi dùng thiết bị nhập của Apple, chuyển động của ngón tay trên trackpad hoặc chuột tương ứng 1:1 với chuyển động của đối tượng đang cuộn
    Những kiểu “cải tiến” như vậy thường tạo cảm giác như đang cuộn trong mật đường
    Nói chung, đừng cố cải thiện hành vi mặc định của trình duyệt

  • Một trong những điều tôi ghét ở web hiện đại lộn xộn là việc đụng vào History API
    Khi nhấn một liên kết có vẻ thú vị từ nơi như HN, vào trang rồi cuộn, mọi tiêu đề hoặc thậm chí các phần tử chẳng mấy quan trọng cũng thêm mục vào lịch sử truy cập
    Muốn quay lại trang gốc thì phải bấm nút quay lại đến cả triệu lần
    Tôi ghét tất cả những ai làm chuyện này

    • Tôi cũng muốn thêm cuộn vô hạn vào đây
      Chỉ cần dùng phân trang là được
      Có thể liên kết, tìm kiếm, điều hướng, và hoạt động đúng với lịch sử truy cập
      Cuộn vô hạn phá hỏng tất cả những điều đó mà chẳng có lý do gì đáng kể
  • Thực ra ở đây có hai vấn đề lâu đời như chính web: kỳ vọng thấp và sự thiếu vắng các tiêu chuẩn/chuẩn mực để định nghĩa con người hoặc thực hành nghề nghiệp
    Nhìn các tin tuyển dụng ngày nay thì toàn là “Senior Fullstack Engineer”, nhưng đọc vào thì thứ họ thật sự muốn thường là một tổ hợp Java hoặc Python, R, Spring, SQL
    Nếu không phải fullstack mà vẫn viết như vậy thì chỉ làm lãng phí thời gian của mọi người, đồng thời gửi tín hiệu ra công chúng rằng họ không hiểu hoặc không quan tâm đến công nghệ
    Trong lập trình, điều này được gọi là “vấn đề X/Y”. Đây là một anti-pattern: đáng ra phải giải quyết trạng thái đích X mong muốn, nhưng thay vào đó lại chỉ nói về cách tiếp cận Y mà mình muốn dùng
    Vì vậy nhà tuyển dụng nhận 500 hồ sơ cho một tin đăng mà vẫn cảm thấy không có ai phù hợp
    Điểm khởi đầu phải là mục tiêu: nên viết kiểu “Chúng tôi tuyển người để xây dựng ứng dụng client/server như thế này, ứng viên phải viết và hỗ trợ các tính năng X, Y, Z, còn các ràng buộc là A, B, C”
    Lý do các công ty không làm được như vậy thường là vì họ không biết mình thực sự đang làm gì, và đã ôm một đống công nghệ hỏng sau khi đi qua nhiều con đường sai lầm. Vì thế mới gọi là nợ kỹ thuật
    Khi mục tiêu rõ ràng như vậy, trong phỏng vấn cả công ty lẫn ứng viên đều biết cần kiểm tra điều gì và có thể sàng lọc nhau phù hợp. Nếu không, nó trở thành một quy trình kinh khủng như pha trộn giữa hẹn hò giấu mặt và gameshow
    Ví dụ, có thể nêu rõ rằng công ty tuyển người để xây dựng một ứng dụng hội nghị truyền thông phân tán cao, nhà phát triển sẽ viết TypeScript, nối luồng dữ liệu từ socket qua pipe, làm việc ở cả trình duyệt lẫn máy chủ và viết tự động hóa kiểm thử
    Các ràng buộc vận hành bao gồm tuân thủ WCAG AA, checklist tuân thủ quyền riêng tư do đội pháp lý lập, các cân nhắc hiệu năng nhắm đến tốc độ thực thi và độ trễ mạng; ứng viên lý tưởng phải thể hiện được trong phỏng vấn các giải pháp cho độ trễ mạng, logic ứng dụng trình duyệt và quản lý trạng thái dữ liệu streaming