Dừng sử dụng CSS trong JavaScript khi lập trình Web
CSS không phải dùng cho tất cả các trường hợp. Rất nhiều dự án JavaScript gặp vấn đề vì chọn sai style. Bài viết này liệt kê các quan niệm sai lầm thông thường (huyền thoại) và các giải pháp cho những vấn đề hiện tại của CSS. Bài viết này không có ý công kích một cá nhân hay dự án cụ ...
CSS không phải dùng cho tất cả các trường hợp. Rất nhiều dự án JavaScript gặp vấn đề vì chọn sai style. Bài viết này liệt kê các quan niệm sai lầm thông thường (huyền thoại) và các giải pháp cho những vấn đề hiện tại của CSS.
Bài viết này không có ý công kích một cá nhân hay dự án cụ thể. Tôi mô tả “CSS trong JavaScript” như styled-components vì đây là xu hướng hiện tại trong React.
Các tác giả của styled-components (Max Stoiber, Glen Maddern và tất cả những người đóng góp) họ là những người thông minh với ý tưởng sáng tạo và mục đích tốt.
Lịch sử của CSS và JavaScript
Ngôn ngữ Cascading Style Sheets (CSS) được tạo ra để mô tả, trình bày một document được viết bằng ngôn ngữ đánh dấu. JavaScript đã được tạo ra như là một “glue language (ngôn ngữ keo)” để lắp ráp các component như hình ảnh và các plugin. Qua nhiều năm, JavaScript đã phát triển và biến đổi để thích ứng với các trường hợp sử dụng mới.
Sự ra đời của thuật ngữ Ajax (2005) đánh dấu một cột mốc quan trọng. Đây là khi các thư viện như Prototype, jQuery, MooTools đã thu hút được các cộng đồng lớn cùng nỗ lực hợp tác để giải quyết các vấn đề fetch data trong background và các trình duyệt không liên quan. Điều này tạo ra một vấn đề mới: làm thế nào để quản lý tất cả các dữ liệu?
Đến năm 2010, Backbone.js xuất hiện như một tiêu chuẩn ngành để quản lý state của ứng dụng. Không lâu sau, Knockout và Angular khiến mọi người hấp dẫn với ràng buộc hai chiều (two-way binding). Không lâu sau đó, React và Flux xuất hiện. Điều này bắt đầu kỷ nguyên của Single-Page Applications (ứng dụng một trang – SPA), các ứng dụng bao gồm nhiều component.
Còn về CSS?
Trong tài liệu styled-components :
“Vấn đề với CSS thì đơn giản nó được xây dựng trong một kỷ nguyên mà web bao gồm các tài liệu. Năm 1993 web được tạo ra để trao đổi các tài liệu khoa học là chủ yếu , và CSS đã được giới thiệu như là một giải pháp để trình bày các tài liệu. Tuy nhiên, hiện nay chúng tôi đang xây dựng các ứng dụng phong phú, tương tác, người dùng, và CSS thì không phù hợp cho trường hợp sử dụng này.”
Tôi không đồng ý.
CSS đã phát triển để theo kịp yêu cầu của UI hiện đại. Số lượng các tính năng mới đã có trong thập kỷ qua là quá hợp lý (pseudo-classes, pseudo-elements, CSS variables, media queries, keyframes, combinators, columns, flex, grid, computed values, …).
Trong hoàn cảnh UI, “component” là một đoạn bị cô lập của một tài liệu (<button /> là một component). CSS được thiết kế theo phong cách các tài liệu, bao gồm tất cả các component. Vậy vấn đề là gì?
Thì như câu nói: “Sử dụng đúng công cụ cho đúng công việc”.
Styled-components
styled-components cho phép viết CSS trong JavaScript sử dụng các ký tự mẫu được gắn thẻ. Loại bỏ ánh xạ giữa các component và styles — component được tạo thành cấu trúc style ở low-level, ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import React from 'react'; import styled from 'styled-components'; // Create a <Title> react component that renders an <h1> which is // centered, palevioletred and sized at 1.5em const Title = styled.h1` font-size: 1.5em; text-align: center; color: palevioletred; `; // Create a <Wrapper> react component that renders a <section> with // some padding and a papayawhip background const Wrapper = styled.section` padding: 4em; background: papayawhip; `; // Use them like any other React component – except they're styled! <Wrapper> <Title>Hello World, this is my first styled component!</Title> </Wrapper> |
Kết quả:
Live demostyled-components hiện đang có xu hướng như một cách mới để tạo thành các component trong React.
Cho phép làm rõ một điều: styled-components chỉ là một lớp trừu tượng higher-level hơn trên đầu trang của CSS. Tất cả những gì nó làm là phân tích cú pháp CSS của bạn được mô tả trong JavaScript và tạo các phần tử JSX được ánh xạ tới CSS.
Tôi không thích xu hướng này bởi vì nó có rất nhiều quan niệm sai lầm.
Tôi đã khảo sát mọi người về lý do sử dụng styled-components trên IRC, Reddit và Discord và biên soạn thành một danh sách các câu trả lời chung cho việc chọn styled-components khi nào. Tôi gọi chúng là myths (huyền thoại).
Myths #1: Giải quyết xung đột global namespace và style
Tôi gọi đây là myths (huyền thoại) vì nghe như những vấn đề này không thể giải quyết. Các module CSS, Shadow DOM và vô số các quy ước đặt tên (như BEM) đã được cộng đồng giải quyết từ lâu.
styled-components (chỉ như là một module CSS) sẽ thực hiện việc đặt tên thay chúng ta. Vì con người dễ mắc sai lầm còn máy tính thì ít khi mắc sai lầm.
Theo ý kiến cá nhân, đó không phải là một lý do đủ để bắt đầu sử dụng styled-components.
Myth #2: Sử dụng styled-components giúp code ngắn gọn hơn
Thường đi kèm với một ví dụ như:
1 2 3 4 |
<TicketName></TicketName> <div className={styles.ticketName}></div> |
Trước hết – nó không quan trọng. Không có sự khác biệt đáng kể.
Thứ hai, đó không phải là sự thật. Tổng số ký tự phụ thuộc vào cách đặt tên.
1 2 3 4 |
<TinyBitLongerStyleName></TinyBitLongerStyleName> <div className={styles.longerStyleName}></div> |
Cũng tương tự như vậy đối với việc xây dựng các style như bạn sẽ thấy trong bài viết (Myth 5: Làm đơn giản việc đặt điều kiện cho các style component). styled-components chỉ thành công trong việc làm ngắn gọn trong trường hợp các component cơ bản nhất.
Myth 3: Sử dụng styled components làm cho bạn suy nghĩ nhiều hơn về ý nghĩa (semantics)
Điều này sai ngay từ đầu. Phong cách (style) và ý nghĩa (semantics) đại diện cho các vấn đề khác nhau và yêu cầu các giải pháp khác nhau. Để trích dẫn Adam Morse (mrmrs):
Nội dung semantics KHÔNG HỀ TƯƠNG ĐỒNG VỚI VISUAL STYLE. Khi tôi sử dụng để xây dựng những thứ với đồ chơi lego tôi không bao giờ nghĩ rằng “oh đây là một mảnh cho một khối động cơ” mà tôi nghĩ “oh thật tươi mát này là một lego màu xanh 1×4 và tôi có thể làm bất cứ điều gì tôi muốn với nó”. Mọi chuyện không thành vấn đề nếu tôi đang xây dựng cơ sở dưới nước dưới biển hoặc máy bay và tôi biết chính xác cách sử dụng khối lego đó.
– http://mrmrs.io/writing/2016/03/24/scalable-css/
(Tôi khuyên bạn nên đọc Scalable CSS của Adam).
Ví dụ:
1 2 3 4 5 6 7 8 |
<PersonList> <PersonListItem> <PersonFirstName>Foo</PersonFirstName> <PersonLastName>Bar</PersonLastName> </PersonListItem> </PersonList> |
Semantics là về việc sử dụng các thẻ bên phải để xây dựng đánh dấu. Bạn có biết những gì về các thẻ HTML sẽ biên dịch các component này? Không, bạn không biết.
So sánh nó với:
1 2 3 4 5 6 7 8 |
<ol> <li> <span className={styles.firstName}>Foo</span> <span className={styles.lastName}>Bar</span> </li> </ol> |
Myth 4: Nó giúp bạn dễ dàng mở rộng style
Trong v1, bạn có thể mở rộng các style bằng styled(StyledComponent) ; v2 giới thiệu phương thức extend để mở rộng các style hiện có, ví dụ:
1 2 3 4 5 6 7 8 |
const Button = styled.button` padding: 10px; `; const TomatoButton = Button.extend` color: #f00; `; |
Điều đó thật tuyệt. Nhưng bạn có thể làm điều này trong CSS (hoặc sử dụng thành phần CSS module hoặc sử dụng SASS tổ hợp thừa kế@extend).
1 2 3 4 5 6 7 8 |
button { padding: 10px; } button.tomato-button { color: #f00; } |
Điều nào làm cho tiếp cận JavaScript dễ dàng hơn?
Myth 5: Làm đơn giản việc đặt điều kiện cho các style component
Ý tưởng là bạn có thể tạo thành các style component dựa trên props của chúng, ví dụ:
1 2 3 4 5 |
<Button primary /> <Button secondary /> <Button primary active={true} /> |
Điều này có rất nhiều ý nghĩa trong thế giới React. Sau cùng, hành vi của component được kiểm soát bằng cách sử dụng props. Liệu nó có ý nghĩa trực tiếp đính kèm giá trị prop vào styles? Có lẽ. Nhưng hãy nhìn vào việc hoàn thiện component:
1 2 3 4 5 6 7 |
styled.Button` background: ${props => props.primary ? '#f00' : props.secondary ? '#0f0' : '#00f'}; color: ${props => props.primary ? '#fff' : props.secondary ? '#fff' : '#000'}; opacity: ${props => props.active ? 1 : 0}; `; |
Tạo một style sheet theo điều kiện, sử dụng sức mạnh của JavaScript sẽ cho bạn rất nhiều quyền năng. Tuy nhiên, điều đó cũng có nghĩa là style này khó giải thích hơn nhiều. So sánh nó với CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
button { background: #00f; opacity: 0; color: #000; } button.primary, button.seconary { color: #fff; } button.primary { background: #f00; } button.secondary { background: #0f0; } button.active { opacity: 1; } |
Trong trường hợp này, CSS ngắn hơn (222 ký tự) và dễ theo dõi hơn (theo ý kiến chủ quan). Hơn nữa, trong CSS, bạn sẽ sử dụng preprocessor để làm cho nó ngắn hơn và nhóm lại, ví dụ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
button { background: #00f; opacity: 0; color: #000; &.primary, &.seconary { color: #fff; } &.primary { background: #f00; } &.secondary { background: #0f0; } &.active { opacity: 1; } } |
Myth 6: Cho phép tổ chức code tốt hơn
Có một vài người nói với tôi rằng họ thích styled-components bởi vì nó cho phép để style và JavaScript trong cùng một file.
Tôi có thể thấy nhiều file cho cùng một component có thể nhàm chán, nhưng nhét style và markup vào một file là một giải pháp khủng khiếp. Nó làm cho version control khó theo dõi.
Nếu bạn phải để CSS và JavaScript trong cùng một file, hãy xem xét sử dụng css-literal-loader. Sau này nó cho phép bạn extract CSS tại thời điểm xây dựng bằng cách sử dụng plugin extract-text-webpack và sử dụng cấu hình loader tiêu chuẩn của bạn để xử lý CSS.
Myth 7: Nó làm cho DX hoàn hảo. Là tool tuyệt vời!
Bạn rõ ràng đã không sử dụng styled-components.
- Khi có vấn đề gì xảy ra với style, toàn bộ ứng dụng sẽ sụp đổ với hàng loạt lỗi (kinh nghiệm từ sử dụng v2). Ngược lại điều này với CSS, trong đó “style error” sẽ chỉ làm cho phần tử đó không thể biên dịch.
- Các phần tử không có className có thể nhận diện được, do đó bạn sẽ kết thúc việc chuyển đổi giữa cây phần tử React và cây DOM DevTools khi debug (đối với record, trong v2 điều này có thể được giải quyết bằng cách sử dụngbabel-plugin-styled-components).
- Không linting (có một plugin stylelint trong phát triển).
- Style không có giá trị đơn giản là bị bỏ qua
- Highlight cú pháp, hoàn thiện code và các tính năng IDE khác được hỗ trợ trong vài IDE. Nếu bạn đang làm việc với các cơ quan tài chính hoặc chính phủ, rất có thể Atom IDE không nằm trong danh sách.
Myth 8: Mọi việc đều hiệu suất tốt hơn, bất cứ điều gì kích thước cũng nhỏ hơn
- Vì nó là viết tắt,styled-components không thể được extract vào một file CSS tĩnh (chẳng hạn như sử dụng https://github.com/webpack-contrib/extract-text-webpack-plugin). Nghĩa là trình duyệt của bạn không thể bắt đầu biên dịch các style cho đến khi styled-components phân tích chúng và thêm chúng vào DOM.
- Thiếu các file riêng biệt có nghĩa là bạn không thể cache một cách riêng biệt CSS và JavaScript.
- Tất cả các styled component được gói trong một HoC bổ sung bởi bản chất của chúng. Đó là một performance không cần thiết tác động. Lỗ hổng kiến trúc giống nhau là lý do tại sao tôi đã ngưng https://github.com/gajus/react-css-modules (và tạo https://github.com/gajus/babel-plugin-react-css-modules) .
- Bởi vì trong HoC, nếu bạn đang biên dịch phía máy chủ, điều này trả về kết quả một markup document lớn hơn rất nhiều.
Myth 9: Cho phép phát triển các responsive component
Điều này chủ yếu thảo luận về khả năng tạo style component theo môi trường xung quanh, ví dụ: Kích thước container parent, số của children, v.v …
Trước tiên, styled-components không liên quan gì đến điều này. Nó nằm ngoài phạm vi của dự án. Bạn tốt hơn là trực tiếp thiết lập các giá trị style của các component trong trường hợp này để tránh các phát sinh thêm.
Tuy nhiên, truy vấn phần tử là một vấn đề thú vị và đó là một chủ đề được quan tâm trong CSS, chủ yếu là cho EQCSS của dự án và các đối tác của nó. Các truy vấn phần tử tương tự như các truy vấn @media trong cú pháp của chúng, ngoại trừ các truy vấn phần tử hoạt động trên các phần tử cụ thể.
1 2 3 |
@element {selector} and {condition} [ and {condition} ]* { {css} } |
- {selector} Là một bộ chọn CSS nhắm mục tiêu một hoặc nhiều phần tử. Ví dụ:#id hoặc .class
- {condition} bao gồm một measure và một giá trị.
- {css} Có thể chứa: Bất kỳ quy tắc CSS hợp lệ nào. (Ví dụ:#id div { color: red })
Các truy vấn phần tử cho phép tạo thành phần tử theo các điều kiện nhưmin-awidth, max-awidth, min-height, max-height, min-characters, max-characters, min-children, max-children, min-lines, max-lines, min-scroll-x, max-scoll-x, và những cái khác (xem http://elementqueries.com/).
Nhưng khoan!
Hầu hết (nếu không phải tất cả) những điều này có thể được giải quyết về lâu dài, hoặc bởi cộng đồng, thay đổi trong React hoặc trongstyled-components . Nhưng có một số điểm? CSS đã được hỗ trợ rộng rãi, nó có cộng đồng lớn.
Điểm của bài báo này không nhằm ngăn người đọc sử dụng “CSS” trong JavaScript hoặc sử dụngstyled-components. Tạo style bằng cách sử dụng styled-components có một trường hợp rất tuyệt vời: hỗ trợ nhiều nền tảng tốt hơn. Chỉ là không sử dụng vì những lý do không phù hợp.
Vậy những gì sẽ sử dụng cho ngày nay?
Còn quá sớm để sử dụng Shadow DOM v1 (hỗ trợ toàn cầu 51%). Sử dụng CSS với một trong những quy ước đặt tên (tôi khuyên bạn nên BEM). Nếu bạn đang lo lắng về sự va chạm của tên lớp (hoặc quá lười để sử dụng BEM), sử dụng module CSS. Nếu bạn đang phát triển cho trang web React, hãy cân nhắc sử dụng babel-plugin-react-css-modules. Nếu bạn đang phát triển React native, styled-components là lựa chọn hoàn hảo.
Techtalk via Medium