Tạo thành phần nút

Tổng quan cơ bản về cách tạo các thành phần <button> thích ứng màu, phản hồi và dễ tiếp cận.

Trong bài đăng này, tôi muốn chia sẻ suy nghĩ của mình về cách tạo ra màu sắc thích ứng, và có khả năng thích ứng cao <button>. Thử bản minh hoạxem nguồn

Các nút được tương tác thông qua bàn phím và chuột trong giao diện sáng và tối.

Nếu bạn thích xem video hơn, sau đây là phiên bản của bài đăng này trên YouTube:

Tổng quan

Hỗ trợ trình duyệt

  • Chrome: 1.
  • Cạnh: 12.
  • Firefox: 1.
  • Safari: 1.

Nguồn

Chiến lược phát hành đĩa đơn <button> được xây dựng để tương tác của người dùng. Sự kiện click của nó kích hoạt từ bàn phím, chuột, chạm, giọng nói, v.v. với các quy tắc thông minh về thời gian. Điều này cũng đi kèm với một số kiểu mặc định trong mỗi trình duyệt, để bạn có thể sử dụng trực tiếp mà không cần bất kỳ tuỳ chỉnh nào. Sử dụng color-scheme để chọn vào cả nút sáng và tối do trình duyệt cung cấp.

Ngoài ra còn có các loại các nút, mỗi thành phần được hiển thị trong mã nhúng Codepen trước đó. <button> không có loại sẽ thích ứng với việc nằm trong <form>, thay đổi thành loại gửi.

<!-- buttons -->
<button></button>
<button type="submit"></button>
<button type="button"></button>
<button type="reset"></button>

<!-- button state -->
<button disabled></button>

<!-- input buttons -->
<input type="button" />
<input type="file">

Trong Thử thách GUI của tháng này, mỗi nút sẽ nhận được các kiểu để giúp phân biệt ý định của chúng một cách trực quan. Đặt lại các nút sẽ có màu cảnh báo vì chúng có tính phá hoại và gửi các nút sẽ nhận được văn bản có màu xanh dương, nên chúng được quảng bá nhiều hơn một chút so với bình thường các nút.

Xem trước tập hợp hoàn thiện gồm tất cả các loại nút, hiển thị trong biểu mẫu chứ không phải trong biểu mẫu, với các điểm bổ sung đẹp mắt cho nút biểu tượng và nút được tuỳ chỉnh.
Xem trước tập hợp hoàn thiện gồm tất cả các loại nút, hiển thị trong biểu mẫu chứ không phải trong biểu mẫu, với các bổ sung thú vị cho nút biểu tượng và nút tuỳ chỉnh

Các nút cũng có lớp giả để CSS sử dụng cho việc tạo kiểu. Các lớp này cung cấp hook CSS để tuỳ chỉnh cảm giác của nút: :hover khi chuột nằm trên nút, :active khi chuột hoặc bàn phím đang nhấn và :focus hoặc :focus-visible để hỗ trợ việc tạo kiểu cho công nghệ hỗ trợ.

button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
Bản xem trước tập hợp hoàn thiện gồm tất cả các loại nút trong giao diện tối.
Bản xem trước tập hợp hoàn thiện gồm tất cả các loại nút trong giao diện tối

Markup (note: đây là tên ứng dụng)

Ngoài các loại nút do đặc tả HTML cung cấp, tôi đã thêm một nút có một biểu tượng và một nút có lớp tuỳ chỉnh btn-custom.

<button>Default</button>
<input type="button" value="<input>"/>
<button>
  <svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
    <path d="..." />
  </svg>
  Icon
</button>
<button type="submit">Submit</button>
<button type="button">Type Button</button>
<button type="reset">Reset</button>
<button disabled>Disabled</button>
<button class="btn-custom">Custom</button>
<input type="file">

Sau đó, để kiểm thử, mỗi nút được đặt bên trong một biểu mẫu. Bằng cách này, tôi có thể đảm bảo các kiểu được cập nhật phù hợp cho nút mặc định, nút này hoạt động như một gửi. Tôi cũng chuyển đổi chiến lược biểu tượng, từ SVG cùng dòng sang SVG bị che khuất, để đảm bảo cả hai đều hoạt động hiệu quả như nhau.

<form>
  <button>Default</button>
  <input type="button" value="<input>"/>
  <button>Icon <span data-icon="cloud"></span></button>
  <button type="submit">Submit</button>
  <button type="button">Type Button</button>
  <button type="reset">Reset</button>
  <button disabled>Disabled</button>
  <button class="btn-custom btn-large" type="button">Large Custom</button>
  <input type="file">
</form>

Hiện tại, ma trận kết hợp khá là quá choáng ngợp. Nút Giữa loại, lớp giả và ở trong hoặc ngoài một biểu mẫu, có hơn 20 để kết hợp các nút. Đây là một điều hữu ích khi CSS có thể giúp chúng ta trình bày rõ ràng chúng một cách rõ ràng!

Hỗ trợ tiếp cận

Các thành phần nút có thể truy cập được một cách tự nhiên, nhưng có một số các tính năng nâng cao.

Di chuột và lấy nét cùng nhau

Tôi muốn nhóm :hover:focus cùng với chức năng :is() bộ chọn giả. Điều này giúp đảm bảo rằng giao diện của tôi luôn cân nhắc đến bàn phím và phong cách công nghệ hỗ trợ.

button:is(:hover, :focus) {
  
}
Xem bản minh hoạ!

Vòng lấy nét tương tác

Tôi thích tạo ảnh động cho vòng lấy nét cho những người dùng bàn phím và công nghệ hỗ trợ. N thực hiện điều này bằng cách tạo ảnh động cho đường viền cách nút 5px, nhưng chỉ khi nút không hoạt động. Thao tác này tạo ra một hiệu ứng làm cho vòng lấy nét thu nhỏ lại kích thước nút khi được nhấn.

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

Đảm bảo độ tương phản màu truyền qua

Có ít nhất 4 tổ hợp màu sáng và tối khác nhau cần xem xét độ tương phản màu: nút, nút gửi, nút đặt lại và nút tắt. VisBug được dùng ở đây để kiểm tra và hiển thị tất cả điểm số của học viên cùng một lúc:

Đang ẩn biểu tượng để những người không xem được

Khi tạo nút biểu tượng, biểu tượng đó phải hỗ trợ trực quan cho văn bản của nút. Điều này cũng có nghĩa là biểu tượng không có giá trị đối với người có tầm nhìn tổn thất. Rất may là trình duyệt có cung cấp cách ẩn các mục khỏi trình đọc màn hình để những người bị mất thị lực không bận tâm đến nút trang trí hình ảnh:

<button>
  <svg … aria-hidden="true">...</svg>
  Icon Button
</button>
Công cụ của Chrome cho nhà phát triển cho thấy cây hỗ trợ tiếp cận cho nút. Cây sẽ bỏ qua hình ảnh nút vì nó có aria-hidden được đặt thành true.
Công cụ của Chrome cho nhà phát triển cho thấy cây hỗ trợ tiếp cận cho nút. Cây sẽ bỏ qua hình ảnh nút vì nó có aria-hidden được đặt thành true

Kiểu

Trong phần tiếp theo này, trước tiên, tôi thiết lập hệ thống thuộc tính tuỳ chỉnh để quản lý các kiểu thích ứng của nút. Với các thuộc tính tuỳ chỉnh đó, tôi có thể bắt đầu chọn các phần tử và tuỳ chỉnh hình thức của chúng.

Chiến lược thuộc tính tuỳ chỉnh thích ứng

Chiến lược thuộc tính tuỳ chỉnh được sử dụng trong Thử thách về giao diện người dùng đồ hoạ này rất giống với dùng để tạo bảng phối màu. Cho hệ thống màu sáng và tối thích ứng, mỗi thuộc tính tuỳ chỉnh cho mỗi giao diện là được xác định và đặt tên tương ứng. Sau đó, một thuộc tính tùy chỉnh duy nhất được sử dụng để lưu giữ giá trị hiện tại của giao diện và được gán cho thuộc tính CSS. Sau đó, đĩa đơn có thể cập nhật thuộc tính tuỳ chỉnh thành một giá trị khác, rồi cập nhật nút phong cách.

button {
  --_bg-light: white;
  --_bg-dark: black;
  --_bg: var(--_bg-light);

  background-color: var(--_bg);
}

@media (prefers-color-scheme: dark) {
  button {
    --_bg: var(--_bg-dark);
  }
}

Điều tôi thích là giao diện sáng và tối đều mang tính khai báo và rõ ràng. Chiến lược phát hành đĩa đơn gián tiếp và trừu tượng được giảm tải vào thuộc tính tuỳ chỉnh --_bg, đây là chức năng "phản ứng" duy nhất bất động sản; --_bg-light--_bg-dark là tĩnh. Ngoài ra, bạn cũng dễ dàng nhận thấy rằng giao diện sáng là giao diện mặc định và màu tối chỉ được áp dụng có điều kiện.

Chuẩn bị để đảm bảo tính nhất quán trong thiết kế

Bộ chọn dùng chung

Bộ chọn sau được dùng để nhắm mục tiêu tất cả các loại nút và hơi choáng ngợp lúc đầu. :where() là nên việc tuỳ chỉnh nút không cần cụ thể. Các nút thường được điều chỉnh cho các tình huống thay thế và bộ chọn :where() giúp đảm bảo tác vụ rất dễ dàng. Bên trong :where(), mỗi loại nút đều được chọn, bao gồm ::file-selector-button, không được đã dùng bên trong :is() hoặc :where().

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  
}

Tất cả thuộc tính tuỳ chỉnh sẽ nằm trong phạm vi của bộ chọn này. Thời gian xem xét tất cả thuộc tính tuỳ chỉnh! Có khá nhiều thuộc tính tuỳ chỉnh được sử dụng trong giao diện này . Tôi sẽ mô tả từng nhóm khi chúng ta bắt đầu, sau đó chia sẻ màn tối và giảm thiểu ngữ cảnh chuyển động ở cuối phần này.

Màu nhấn của nút

Các nút và biểu tượng gửi là nơi tuyệt vời để tạo hiệu ứng nổi bật:

--_accent-light: hsl(210 100% 40%);
--_accent-dark: hsl(210 50% 70%);
--_accent: var(--_accent-light);

Màu văn bản nút

Màu văn bản trên nút không phải là màu trắng hoặc đen, mà có phiên bản đã được làm tối hoặc sáng trong tổng số --_accent đang sử dụng hsl() và luôn gắn bó với sắc thái 210:

--_text-light: hsl(210 10% 30%);
--_text-dark: hsl(210 5% 95%);
--_text: var(--_text-light);

Màu nền của nút

Nền của các nút theo cùng một mẫu hsl(), ngoại trừ giao diện sáng các nút—các nút đó được đặt thành màu trắng để bề mặt của chúng làm cho chúng xuất hiện gần với người dùng hoặc trước các thiết bị khác:

--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);

Nền của nút hợp lý

Màu nền này dùng để làm cho một bề mặt xuất hiện phía sau các bề mặt khác, hữu ích cho nền của đầu vào tệp:

--_input-well-light: hsl(210 16% 87%);
--_input-well-dark: hsl(204 10% 10%);
--_input-well: var(--_input-well-light);

Khoảng đệm nút

Giãn cách xung quanh văn bản trong nút được thực hiện bằng cách sử dụng toán tử ch một đơn vị, chiều dài tương đối so với cỡ chữ. Điều này trở nên quan trọng khi quy mô lớn các nút có thể tăng kích thước font-size và tỷ lệ của nút theo tỷ lệ:

--_padding-inline: 1.75ch;
--_padding-block: .75ch;

Đường viền nút

Bán kính đường viền của nút được lưu trữ trong một thuộc tính tuỳ chỉnh để nội dung nhập vào tệp có thể khớp với các nút khác. Màu đường viền tuân theo màu thích ứng đã thiết lập hệ thống:

--_border-radius: .5ch;

--_border-light: hsl(210 14% 89%);
--_border-dark: var(--_bg-dark);
--_border: var(--_border-light);

Hiệu ứng làm nổi bật khi di chuột qua nút

Các thuộc tính này thiết lập thuộc tính kích thước để chuyển đổi khi tương tác và màu đánh dấu tuân theo hệ thống màu thích ứng. Chúng tôi sẽ đề cập đến cách tương tác sau trong bài đăng này, nhưng cuối cùng những thông tin này vẫn được sử dụng cho box-shadow hiệu ứng:

--_highlight-size: 0;

--_highlight-light: hsl(210 10% 71% / 25%);
--_highlight-dark: hsl(210 10% 5% / 25%);
--_highlight: var(--_highlight-light);

Độ bóng văn bản nút

Mỗi nút có một kiểu bóng văn bản tinh tế. Điều này giúp văn bản nằm trên nút này, cải thiện mức độ dễ đọc và thêm một lớp trau chuốt cho bản trình bày.

--_ink-shadow-light: 0 1px 0 var(--_border-light);
--_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%);
--_ink-shadow: var(--_ink-shadow-light);

Biểu tượng nút

Biểu tượng có kích thước của 2 ký tự nhờ đơn vị ch có độ dài tương đối để giúp biểu tượng điều chỉnh theo tỷ lệ tương ứng với văn bản trên nút. Chiến lược phát hành đĩa đơn màu biểu tượng dựa vào --_accent-color để mang đến giao diện thích ứng và phù hợp .

--_icon-size: 2ch;
--_icon-color: var(--_accent);

Bóng nút

Để bóng thích ứng thích hợp với ánh sáng và tối, chúng cần phải chuyển cả hai bóng màu sắc và độ mờ. Bóng giao diện sáng phù hợp nhất khi bóng mờ và được phủ màu theo màu sắc bề mặt mà chúng phủ lên. Bóng của giao diện tối cần phải tối hơn và bão hoà hơn để chúng có thể phủ lên các màu tối hơn của bề mặt.

--_shadow-color-light: 220 3% 15%;
--_shadow-color-dark: 220 40% 2%;
--_shadow-color: var(--_shadow-color-light);

--_shadow-strength-light: 1%;
--_shadow-strength-dark: 25%;
--_shadow-strength: var(--_shadow-strength-light);

Với màu sắc và độ mạnh thích ứng, tôi có thể tập hợp hai độ sâu bóng:

--_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%));

--_shadow-2: 
  0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)),
  0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%));

Ngoài ra, để tạo cho các nút giao diện hơi 3D, bóng hộp 1px tạo ra ảo tưởng:

--_shadow-depth-light: 0 1px var(--_border-light);
--_shadow-depth-dark: 0 1px var(--_bg-dark);
--_shadow-depth: var(--_shadow-depth-light);

Hiệu ứng chuyển đổi nút

Theo mẫu dành cho màu thích ứng, tôi tạo 2 thuộc tính tĩnh để giữ các tuỳ chọn hệ thống thiết kế:

--_transition-motion-reduce: ;
--_transition-motion-ok:
  box-shadow 145ms ease,
  outline-offset 145ms ease
;
--_transition: var(--_transition-motion-reduce);

Tất cả tài sản cùng xuất hiện trong bộ chọn

Tất cả tài sản tuỳ chỉnh trong một bộ chọn

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  --_accent-light: hsl(210 100% 40%);
  --_accent-dark: hsl(210 50% 70%);
  --_accent: var(--_accent-light);

--_text-light: hsl(210 10% 30%); --_text-dark: hsl(210 5% 95%); --_text: var(--_text-light);

--_bg-light: hsl(0 0% 100%); --_bg-dark: hsl(210 9% 31%); --_bg: var(--_bg-light);

--_input-well-light: hsl(210 16% 87%); --_input-well-dark: hsl(204 10% 10%); --_input-well: var(--_input-well-light);

--_padding-inline: 1.75ch; --_padding-block: .75ch;

--_border-radius: .5ch; --_border-light: hsl(210 14% 89%); --_border-dark: var(--_bg-dark); --_border: var(--_border-light);

--_highlight-size: 0; --_highlight-light: hsl(210 10% 71% / 25%); --_highlight-dark: hsl(210 10% 5% / 25%); --_highlight: var(--_highlight-light);

--_ink-shadow-light: 0 1px 0 hsl(210 14% 89%); --_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%); --_ink-shadow: var(--_ink-shadow-light);

--_icon-size: 2ch; --_icon-color-light: var(--_accent-light); --_icon-color-dark: var(--_accent-dark); --_icon-color: var(--accent, var(--_icon-color-light));

--_shadow-color-light: 220 3% 15%; --_shadow-color-dark: 220 40% 2%; --_shadow-color: var(--_shadow-color-light); --_shadow-strength-light: 1%; --_shadow-strength-dark: 25%; --_shadow-strength: var(--_shadow-strength-light); --_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%)); --_shadow-2: 0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)), 0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%)) ;

--_shadow-depth-light: hsl(210 14% 89%); --_shadow-depth-dark: var(--_bg-dark); --_shadow-depth: var(--_shadow-depth-light);

--_transition-motion-reduce: ; --_transition-motion-ok: box-shadow 145ms ease, outline-offset 145ms ease ; --_transition: var(--_transition-motion-reduce); }

Các nút mặc định hiển thị trong giao diện sáng và tối cạnh nhau.

Điều chỉnh giao diện tối

Giá trị của mẫu đạo cụ tĩnh -light-dark sẽ trở nên rõ ràng khi các thành phần trong giao diện tối được thiết lập:

@media (prefers-color-scheme: dark) {
  :where(
    button,
    input[type="button"],
    input[type="submit"],
    input[type="reset"],
    input[type="file"]
  ),
  :where(input[type="file"])::file-selector-button {
    --_bg: var(--_bg-dark);
    --_text: var(--_text-dark);
    --_border: var(--_border-dark);
    --_accent: var(--_accent-dark);
    --_highlight: var(--_highlight-dark);
    --_input-well: var(--_input-well-dark);
    --_ink-shadow: var(--_ink-shadow-dark);
    --_shadow-depth: var(--_shadow-depth-dark);
    --_shadow-color: var(--_shadow-color-dark);
    --_shadow-strength: var(--_shadow-strength-dark);
  }
}

Nút này không chỉ đọc tốt mà người sử dụng các nút tuỳ chỉnh này còn có thể sử dụng đạo cụ trần và tự tin rằng chúng sẽ thích ứng theo lựa chọn ưu tiên của người dùng.

Giảm khả năng điều chỉnh chuyển động

Nếu người dùng truy cập này chấp nhận chuyển động, hãy chỉ định --_transition cho var(--_transition-motion-ok):

@media (prefers-reduced-motion: no-preference) {
  :where(
    button,
    input[type="button"],
    input[type="submit"],
    input[type="reset"],
    input[type="file"]
  ),
  :where(input[type="file"])::file-selector-button {
    --_transition: var(--_transition-motion-ok);
  }
}

Một số kiểu chung

Các nút và thao tác nhập vào cần có phông chữ inherit để khớp với phông chữ còn lại của trang; nếu không thì trình duyệt sẽ định kiểu. Việc này cũng áp dụng cho letter-spacing. Việc đặt line-height thành 1.5 sẽ đặt hộp chữ cái để tạo khoảng trống cho văn bản ở phía trên và phía dưới:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  /* …CSS variables */

  font: inherit;
  letter-spacing: inherit;
  line-height: 1.5;
  border-radius: var(--_border-radius);
}

Ảnh chụp màn hình cho thấy các nút sau khi áp dụng kiểu trước đó.

Tạo kiểu nút

Điều chỉnh bộ chọn

Bộ chọn input[type="file"] không phải là một phần nút của đầu vào, pseudo-element ::file-selector-button là, vì vậy tôi đã xoá input[type="file"] khỏi danh sách:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  
}

Điều chỉnh con trỏ và thao tác chạm

Trước tiên, tôi tạo kiểu con trỏ theo kiểu pointer, điều này giúp nút biểu thị cho những người dùng chuột thấy rằng công cụ đó có tính tương tác. Sau đó, tôi thêm touch-action: manipulation vào không cần chờ đợi và quan sát một lượt nhấp đúp tiềm năng, giúp các nút hoạt động nhanh hơn:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  cursor: pointer;
  touch-action: manipulation;
}

Màu và đường viền

Tiếp theo, tôi tuỳ chỉnh cỡ chữ, màu nền, màu văn bản và màu đường viền, sử dụng một số của các thuộc tính tuỳ chỉnh thích ứng đã thiết lập trước đó:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  font-size: var(--_size, 1rem);
  font-weight: 700;
  background: var(--_bg);
  color: var(--_text);
  border: 2px solid var(--_border);
}

Ảnh chụp màn hình cho thấy các nút sau khi áp dụng kiểu trước đó.

Bóng

Các nút được áp dụng một số kỹ thuật tuyệt vời. Chiến lược phát hành đĩa đơn text-shadow là thích ứng với sáng và tối, tạo nên hình thức tinh tế dễ chịu cho nút văn bản nằm gọn trên nền. Đối với box-shadow! 3 bóng được gán. Đầu tiên, --_shadow-2, là bóng hộp thông thường. Bóng thứ hai là một trò đánh lừa mắt khiến nút trông có vẻ như nghiêng lên một chút. Bóng cuối cùng là dành cho vùng nổi bật khi di chuột, ban đầu ở kích thước 0, nhưng sẽ có kích thước sau và được chuyển đổi để biểu ngữ xuất hiện phát triển từ nút.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  box-shadow: 
    var(--_shadow-2),
    var(--_shadow-depth),
    0 0 0 var(--_highlight-size) var(--_highlight)
  ;
  text-shadow: var(--_ink-shadow);
}

Ảnh chụp màn hình cho thấy các nút sau khi áp dụng kiểu trước đó.

Bố cục

Tôi đã tạo cho nút một bố cục hộp linh hoạt, cụ thể là bố cục inline-flex sẽ phù hợp với nội dung của nó. Sau đó, tôi căn giữa và căn chỉnh phần tử con theo chiều dọc và chiều ngang trung tâm. Thao tác này sẽ giúp các biểu tượng và để căn chỉnh chính xác.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  display: inline-flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

Ảnh chụp màn hình cho thấy các nút sau khi áp dụng kiểu trước đó.

Giãn cách

Để giãn cách các nút, tôi đã sử dụng gap để giữ các thành phần đồng cấp từ chạm và logic thuộc tính cho khoảng đệm. Vì vậy, nút này giãn cách sẽ phù hợp với mọi bố cục văn bản.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  gap: 1ch;
  padding-block: var(--_padding-block);
  padding-inline: var(--_padding-inline);
}

Ảnh chụp màn hình cho thấy các nút sau khi áp dụng kiểu trước đó.

Trải nghiệm người dùng bằng chuột và cảm ứng

Phần tiếp theo này chủ yếu dành cho người dùng cảm ứng trên thiết bị di động. Đầu tiên tài sản, user-select! dành cho tất cả người dùng; nút này không cho phép văn bản đánh dấu văn bản của nút. Việc này chủ yếu dễ nhận thấy trên thiết bị cảm ứng, khi người dùng nhấn và giữ một nút, cũng như hệ thống đánh dấu văn bản của nút đó.

Nhìn chung, tôi nhận thấy đây không phải là trải nghiệm người dùng có các nút được tích hợp sẵn nên tôi tắt nó bằng cách đặt user-select thành không có. Nhấn vào màu đánh dấu (-webkit-tap-highlight-color) và trình đơn theo bối cảnh của hệ điều hành (-webkit-touch-callout) là các tính năng khác của nút chỉ tập trung vào web không phù hợp với các khái niệm chung đáp ứng kỳ vọng của người dùng, vì vậy, tôi cũng xoá chúng.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

Kiểu chuyển cảnh

Biến --_transition thích ứng được chỉ định cho thuộc tính chuyển đổi:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  transition: var(--_transition);
}

Khi người dùng không chủ động nhấn, hãy điều chỉnh phần đánh dấu bóng khi di chuột qua để mang lại giao diện tiêu điểm đẹp mắt dường như phát triển từ bên trong nút:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
):where(:not(:active):hover) {
  --_highlight-size: .5rem;
}

Khi lấy tiêu điểm, hãy tăng độ lệch đường viền tiêu điểm trên nút, đồng thời tạo cho nút này giao diện tiêu điểm đẹp mắt dường như tăng lên từ bên trong nút:

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

Biểu tượng

Để xử lý các biểu tượng, bộ chọn này có thêm một bộ chọn :where() dành cho SVG trực tiếp phần tử con hoặc phần tử có thuộc tính tuỳ chỉnh data-icon. Đã đặt kích thước biểu tượng với thuộc tính tuỳ chỉnh bằng cách sử dụng các thuộc tính logic cùng dòng và khối. Màu nét chữ đã đặt, cũng như drop-shadow để khớp với text-shadow. flex-shrink được đặt thành 0 nên biểu tượng này sẽ không bao giờ bóp méo. Cuối cùng, tôi chọn các biểu tượng được sắp xếp và chỉ định các kiểu đó ở đây Viết hoa fill: noneround dòng và liên kết dòng:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
) > :where(svg, [data-icon]) {
  block-size: var(--_icon-size);
  inline-size: var(--_icon-size);
  stroke: var(--_icon-color);
  filter: drop-shadow(var(--_ink-shadow));

  flex-shrink: 0;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

Ảnh chụp màn hình cho thấy các nút sau khi áp dụng kiểu trước đó.

Tuỳ chỉnh nút gửi

Tôi muốn các nút gửi có giao diện được quảng bá một chút và tôi đã đạt được điều này bằng cách làm cho màu văn bản của các nút làm màu nhấn:

:where(
  [type="submit"], 
  form button:not([type],[disabled])
) {
  --_text: var(--_accent);
}

Ảnh chụp màn hình cho thấy các nút sau khi áp dụng kiểu trước đó.

Tuỳ chỉnh nút đặt lại

Tôi muốn các nút đặt lại được tích hợp sẵn một số dấu hiệu cảnh báo để cảnh báo người dùng hành vi có khả năng phá hoại của chúng. Tôi cũng chọn tạo kiểu cho giao diện sáng có nhiều điểm nhấn màu đỏ hơn so với giao diện tối. Việc tuỳ chỉnh được thực hiện bằng thay đổi màu cơ bản sáng hoặc tối thích hợp và nút này sẽ cập nhật kiểu:

:where([type="reset"]) {
  --_border-light: hsl(0 100% 83%);
  --_highlight-light: hsl(0 100% 89% / 20%);
  --_text-light: hsl(0 80% 50%);
  --_text-dark: hsl(0 100% 89%);
}

Tôi cũng nghĩ màu viền của tiêu điểm phù hợp với điểm nhấn của màu đỏ. Màu văn bản điều chỉnh từ đỏ đậm thành đỏ nhạt. Tôi tạo màu đường viền so khớp cụm từ này với từ khoá currentColor:

:where([type="reset"]):focus-visible {
  outline-color: currentColor;
}

Ảnh chụp màn hình cho thấy các nút sau khi áp dụng kiểu trước đó.

Tuỳ chỉnh nút bị tắt

Các nút bị vô hiệu hoá có độ tương phản màu kém trong hãy cố gắng nhấn nút đã bị vô hiệu hoá để nút này trông ít hoạt động hơn. Tôi đã kiểm tra từng bộ màu và đảm bảo chúng đã vượt qua, đẩy giá trị độ sáng HSL cho đến khi điểm số được chuyển trong Công cụ cho nhà phát triển hoặc VisBug.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
)[disabled] {
  --_bg: none;
  --_text-light: hsl(210 7% 40%);
  --_text-dark: hsl(210 11% 71%);

  cursor: not-allowed;
  box-shadow: var(--_shadow-1);
}

Ảnh chụp màn hình cho thấy các nút sau khi áp dụng kiểu trước đó.

Tuỳ chỉnh các nút nhập tệp

Nút nhập tệp là vùng chứa span và nút. CSS có thể định kiểu cho vùng chứa đầu vào một chút, cũng như nút lồng nhau, nhưng không span. Vùng chứa này được cấp max-inline-size để nó sẽ không lớn hơn cần thiết, trong khi inline-size: 100% sẽ cho phép chính nó co lại và vừa vặn nhỏ hơn kích thước thực. Màu nền được đặt thành màu thích ứng tối hơn các nền tảng khác, vì vậy giao diện này sẽ nhìn phía sau nút bộ chọn tệp.

:where(input[type="file"]) {
  inline-size: 100%;
  max-inline-size: max-content;
  background-color: var(--_input-well);
}

Nút bộ chọn tệp và nút loại dữ liệu nhập được cung cấp riêng appearance: none để xoá mọi kiểu do trình duyệt cung cấp mà không phải bị ghi đè bởi các kiểu nút khác.

:where(input[type="button"]),
:where(input[type="file"])::file-selector-button {
  appearance: none;
}

Cuối cùng, lề được thêm vào inline-end của nút để đẩy văn bản span ra khỏi nút, tạo ra một số không gian.

:where(input[type="file"])::file-selector-button {
  margin-inline-end: var(--_padding-inline);
}

Ảnh chụp màn hình cho thấy các nút sau khi áp dụng kiểu trước đó.

Các trường hợp ngoại lệ đặc biệt đối với giao diện tối

Tôi đã đặt nền tối hơn cho các nút hành động chính để độ tương phản cao hơn văn bản, giúp quảng cáo trông có vẻ được quảng bá nhiều hơn một chút.

@media (prefers-color-scheme: dark) {
  :where(
    [type="submit"],
    [type="reset"],
    [disabled],
    form button:not([type="button"])
  ) {
    --_bg: var(--_input-well);
  }
}

Ảnh chụp màn hình cho thấy các nút sau khi áp dụng kiểu trước đó.

Tạo biến thể

Để giải trí và vì tính thực tế, tôi chọn trình bày cách tạo một vài các biến thể. Một biến thể rất rực rỡ, tương tự như mức độ thường thấy của các nút chính ánh sáng. Một biến thể khác là lớn. Biến thể cuối cùng có biểu tượng tô màu nền chuyển màu.

Nút phát sáng

Để có được kiểu nút này, tôi đã trực tiếp ghi đè các đạo cụ cơ sở bằng màu xanh dương màu. Mặc dù quá trình này nhanh chóng và dễ dàng, nhưng nó sẽ loại bỏ các đạo cụ và giao diện thích ứng như nhau trong cả giao diện sáng lẫn tối.

.btn-custom {
  --_bg: linear-gradient(hsl(228 94% 67%), hsl(228 81% 59%));
  --_border: hsl(228 89% 63%);
  --_text: hsl(228 89% 100%);
  --_ink-shadow: 0 1px 0 hsl(228 57% 50%);
  --_highlight: hsl(228 94% 67% / 20%);
}

Nút tuỳ chỉnh hiển thị ở chế độ sáng và tối. Nút này có màu xanh dương rực rỡ, giống như các nút hành động chính thông thường.

Nút lớn

Bạn tạo được kiểu nút này bằng cách sửa đổi thuộc tính tuỳ chỉnh --_size. Khoảng đệm và các phần tử không gian khác tương ứng với kích thước này và điều chỉnh theo tỷ lệ tương ứng với kích thước mới.

.btn-large {
  --_size: 1.5rem;
}

Nút lớn hiển thị bên cạnh nút tuỳ chỉnh, lớn hơn khoảng 150 lần.

Nút biểu tượng

Hiệu ứng biểu tượng này không liên quan gì đến các kiểu nút, nhưng có liên quan cho biết cách thực hiện điều đó chỉ với một vài thuộc tính CSS và nút xử lý các biểu tượng không phải là SVG cùng dòng.

[data-icon="cloud"] {
  --icon-cloud: url("https://api.iconify.design/mdi:apple-icloud.svg") center / contain no-repeat;

  -webkit-mask: var(--icon-cloud);
  mask: var(--icon-cloud);
  background: linear-gradient(to bottom, var(--_accent-dark), var(--_accent-light));
}

Nút có biểu tượng hiển thị trong giao diện sáng và tối.

Kết luận

Giờ bạn đã biết cách tôi thực hiện điều đó, bạn sẽ làm cách nào‽ 🙂

Hãy đa dạng hoá phương pháp tiếp cận và tìm hiểu tất cả các cách xây dựng ứng dụng trên web.

Tạo một bản minh hoạ, tweet cho tôi các đường liên kết và tôi sẽ thêm vào vào phần bản phối lại của cộng đồng dưới đây!

Bản phối lại của cộng đồng

Chưa có gì để xem ở đây.

Tài nguyên