Trình giảm thiểu CSS
Nén CSS bằng cách loại bỏ comment và khoảng trắng, và tối ưu hóa các giá trị.
Về việc minify CSS
Cám dỗ giả định rằng vì Brotli nén luồng văn bản quyết liệt như vậy, giá trị biên của một lượt minify riêng đã sụp đổ. Blog kỹ thuật của Sentry lập đúng lập luận đó tháng 4 năm 2024 và kết luận ngược lại: minify vẫn có lợi. Với tốc độ Internet di động trung vị toàn cầu khoảng 53 Mbps và Brotli triển khai phổ quát ở biên CDN, "nếu bạn cạo được dù chỉ 1 KB trên tổng 100 tài nguyên ở mỗi lần tải trang, bạn có thể được thêm 15 ms tốc độ trang cho những người dùng đó". Nhân với cơ sở khách của bất kỳ site phi tầm thường, điều đó trở thành hóa đơn băng thông thật, chi phí pin thật trên thiết bị di động, và thay đổi vị trí thật trên báo cáo Lighthouse.
Cơ chế quan trọng. Gzip và Brotli là các bộ nén không mất mát đa dụng tìm chuỗi byte lặp lại và mã hóa mỗi lặp như tham chiếu lùi vào từ điển cửa sổ trượt. Hai tệp CSS tạo ra cùng hành vi trình duyệt nhưng chứa byte khác nhau sẽ nén thành hai kích thước khác nhau. margin: 10px 10px 10px 10px; và margin:10px giống nhau về ngữ nghĩa, nhưng cái đầu có nhiều ký tự hơn để mã hóa dù phần lớn là lặp, Brotli giỏi tìm lặp nhưng không hiểu hai chuỗi CSS khác nhau về cú pháp diễn đạt cùng một quy tắc. Chỉ một trình minify hiểu CSS mới có thể làm điều đó. Trung tâm học của Cloudflare đặt mức giảm văn bản thô điển hình ở 30-50%; Brotli ở trên thêm khoảng 5-15% nữa, không phải bằng không, và ở quy mô nó cộng dồn lại.
CSS chặn render, và đó là lý do byte quan trọng
Largest Contentful Paint là một trong ba Core Web Vitals; ngưỡng cho "Tốt" là 2,5 giây ở phần trăm thứ 75 của các lần tải. Điểm Performance tổng thể của Lighthouse cân LCP ở 25% tổng. CSS chặn render theo mặc định, khi trình duyệt thấy <link rel="stylesheet">, nó tạm dừng render đến khi tệp được tải và CSSOM được dựng, vì các quy tắc xa hơn trong stylesheet có thể đè quy tắc trước đó và trình duyệt không thể mạo hiểm vẽ ở trạng thái không styled hoặc styled sai. CSS Object Model, khác DOM, không được dựng từng phần, parser cần cả stylesheet để biết quy tắc nào thắng. JavaScript cũng bị chặn ở đó: script không thể chạy an toàn cho đến khi CSSOM hoàn chỉnh. Hệ quả thực tế là mỗi byte CSS chặn render đều nằm trên đường dẫn quan trọng của mọi Core Web Vital. Một bundle minify 100 KB cho bạn lợi khoảng 30 ms trên kết nối 4G nhanh so với 150 KB không minify, nhỏ mỗi trang, nhưng nghiên cứu Vodafone cho thấy doanh số tăng 8% với cải thiện LCP 31%. Hiệu ứng bậc hai còn lớn hơn: LCP nhanh hơn nâng điểm Lighthouse, nâng độ thấy trên Google cho các site mà Web Vitals là tín hiệu xếp hạng đã biết.
Một trình minify CSS thực sự làm gì
- Bỏ khoảng trắng. Khoảng trắng, tab và xuống dòng chỉ tồn tại để con người đọc được bị bỏ. Khoảng trắng trong chuỗi (tên font-family, giá trị content, URL) và khoảng trắng tách các token được giữ,
1px solid redkhông thể trở thành1pxsolidredvì parser sẽ không nhận ra ba giá trị nữa. - Bỏ comment. Khối
/* ... */bị bỏ. Quy ước được tôn trọng rộng rãi là comment bắt đầu bằng/*!được xem là quan trọng, thường là thông báo bản quyền hoặc giấy phép, và được các trình minify production như cssnano, clean-css, lightningcss và esbuild giữ. - Rút gọn đơn vị-không.
0px,0em,0%,0pt,0vwđều rút thành0, vì độ dài không là cùng độ dài bất kể đơn vị. Trường hợp đặc biệt cẩn trọng ("Not All Zeros are Equal" của Miriam Suzanne, 2022): các số 0 bên trongcalc(),min(),max()vàclamp(), và bên trong thuộc tính tùy biến CSS, không thể bỏ đơn vị an toàn vì các quy tắc số học có kiểu của CSS Values and Units Module Level 4 đòi đơn vị để phân biệt chiều dài với số.0strongtransitionkhông thể trở thành0vì thuộc tính đòi giá trị thời gian. - Rút gọn màu hex. Một màu hex sáu chữ số mà mỗi cặp giống nhau có thể viết bằng ba chữ số:
#FFFFFF → #FFF,#336699 → #369. Đặc tả CSS Color định nghĩa dạng ba chữ số đúng tương đương, và đã vậy từ CSS1. - Bỏ dấu chấm phẩy cuối. Dấu chấm phẩy giữa khai báo cuối của một block rule và dấu ngoặc nhọn đóng là tùy chọn, nên
color:red;}trở thànhcolor:red}. Một byte mỗi rule, cộng dồn lại. - Đưa từ khóa về chữ thường. Từ khóa CSS không phân biệt hoa thường, nên
BLOCKvàblocknghĩa giống nhau, nhưng chữ thường nén tốt hơn và tokenize đồng đều. - Rút gọn về shorthand.
margin: 10px 10px 10px 10pxtrở thànhmargin: 10px;margin: 10px 20px 10px 20pxtrở thànhmargin: 10px 20px. Trình minify production biết quy tắc shorthand chomargin,padding,border,border-radius,background,font,transition,animationvà họ grid.
Minify và tối ưu, ranh giới an-toàn-vs-quyết-liệt
Tài liệu cssnano phân biệt giữa preset "default" (chỉ biến đổi an toàn) và preset "advanced" (biến đổi quyết liệt phụ thuộc vào giả định về CSS của bạn). Preset mặc định là cái bạn bật mà không cần suy nghĩ; preset advanced là cái bạn bật sau khi audit, vì một số tối ưu có thể phá mã phụ thuộc vào hành vi cascade tinh tế, tiền tố vendor, hoặc quái dị trình duyệt. Biến đổi advanced có thể sắp xếp lại quy tắc trong stylesheet để cải thiện khả năng nén, rủi ro nếu bạn có fallback có chủ ý các thuộc tính trùng như display: flex; display: grid;. Chúng có thể gộp thân quy tắc giống nhau trong các danh sách selector ngăn cách bằng dấu phẩy. Chúng có thể bỏ như mã chết các khai báo bị ghi đè, với cùng dè chừng về fallback. Chúng có thể chuẩn hóa giá trị display, hàm transform và định danh tùy biến, translate3d(0,0,0) có thể đơn giản hóa thành translate(0) nếu bạn không dựa vào hiệu ứng phụ là đẩy lên GPU. Chúng có thể bỏ tiền tố vendor không dùng theo mục tiêu Browserslist. csso (Yandex, 2011) tự mô tả là "trình tối ưu cấu trúc" hơn là trình minify thuần, với ba hạng biến đổi: dọn dẹp, nén và tái cấu trúc. Lightning CSS mô tả cùng phân chia: lượt "minify" luôn an toàn, cộng tập biến đổi nhận-biết-targets dịch CSS hiện đại sang điều trình duyệt cũ hiểu. Đường ranh trung thực: trình minify là cái bạn có thể áp lên mọi tệp CSS không cần suy nghĩ; trình tối ưu là cái bạn áp với hiểu biết về codebase của mình.
Lược sử ngắn về tooling minify CSS
YUI Compressor (2007). Julien Lecomte của Yahoo công bố YUI Compressor ngày 11 tháng 8 năm 2007. Phiên bản gốc chỉ xử lý JavaScript; ba ngày sau, phiên bản 2.0 thêm hỗ trợ CSS bằng cách tích hợp một trình minify CSS dựa trên regex viết ban đầu bởi Isaac Schlueter cho dùng cá nhân. YUI Compressor là chuẩn de facto trong nhiều năm, đặc biệt trong thế giới Java/Maven và Rails-asset-pipeline; nó vẫn được dùng đến hôm nay, dù bản thân thư viện YUI đã bị Yahoo rút lui năm 2014. Phía CSS của YUI Compressor luôn dựa trên regex, không phải AST, một quyết định thiết kế mà hệ quả vang trong các công cụ phía trình duyệt nhỏ hơn theo sau.
clean-css (2011). Jakub Pawlowicz công bố clean-css dưới tổ chức GoalSmashers trên GitHub năm 2011, giới thiệu nó là "trình tối ưu CSS nhanh và hiệu quả cho Node.js và Web". Đây là trình minify CSS lớn đầu tiên thiết kế riêng cho hệ sinh thái Node.js và trở thành mặc định trong pipeline Grunt và Gulp. Dòng 5.x hiện hành thu hút khoảng 21 triệu lượt tải hàng tuần từ npm, hỗ trợ inline @import, đổi base URL và source map, và có mô hình "mức tối ưu" theo bậc làm rõ phân chia an-toàn-vs-quyết-liệt. csso (2011) ra đời như dự án nội bộ Yandex, công bố với bản quyền 2011 của Sergey Kryzhanovsky dựa trên ý tưởng của Vitaly Harisov. cssnano (tháng 4 năm 2015) của Ben Briggs chọn cách tiếp cận khác: thay vì một trình minify đơn khối, cssnano là gói được tổ chức gồm các plugin PostCSS nhỏ (~30 trong preset mặc định). Nó trở thành trình minify CSS thống trị trong hệ sinh thái JavaScript phần lớn nhờ tính kết hợp đó và vì bản thân PostCSS, framework của Andrey Sitnik công bố lần đầu tháng 11 năm 2013, trở thành nền cho rất nhiều thứ khác (Autoprefixer, Stylelint, pipeline xử lý của Tailwind). cssnano nay ở phiên bản 7.x và là trình minify CSS mặc định trong css-minimizer-webpack-plugin của webpack, trong Next.js, và trong nhiều mặc định framework khác.
Trình minify CSS của esbuild (2020-2021). Evan Wallace, đồng sáng lập Figma, công bố esbuild như "một dự án sở thích tôi viết trong kỳ nghỉ đông 2019-2020". Viết bằng Go, esbuild nhanh gấp 10-100× các bundler dựa trên JavaScript thời đó. Hỗ trợ CSS chín muồi đến 2021; nay nó có mặt khắp nơi như trình minify nền trong Vite, trong tsup, trong vô số template framework. Lightning CSS (2021/2022). Devon Govett, người tạo Parcel, công bố Parcel CSS năm 2021, một parser, transformer, bundler và minify CSS viết từ đầu bằng Rust. Lập luận là tốc độ (10-100× nhanh hơn các công cụ JS-based đang có) cộng tính đúng (parser thật tuân theo đặc tả CSS, không phải pattern-matching bằng regex) cộng compile nhận biết-targets (hạ CSS hiện đại xuống điều trình duyệt cũ hiểu, giống Babel cho JavaScript). Năm 2022 dự án được đổi tên thành Lightning CSS để tách nó khỏi Parcel như công cụ độc lập. Nay nó là pipeline CSS hiện đại được khuyến nghị của Vite, mặc định trong chính Parcel, và một tùy chọn trong css-minimizer-webpack-plugin. Engine thế hệ mới Oxide của Tailwind nhúng nó.
Pipeline CSS hiện đại
Dự án web hiện đại hiếm khi viết CSS thô trực tiếp vào stylesheet. Sass (Hampton Catlin và Natalie Weizenbaum, phát hành đầu năm 2006), Less (Alexis Sellier, 2009) và Stylus (TJ Holowaychuk, 2010) đứng ở đầu pipeline, thêm biến, lồng, mixin, hàm và partial. Bộ biên dịch xuất CSS thuần, sau đó đi qua PostCSS cho các biến đổi như Autoprefixer (áp tiền tố vendor dựa trên Browserslist), gỡ lồng CSS và hạ cấp CSS hiện đại. Chỉ sau tất cả điều đó trình minify mới chạy, trên CSS đã phẳng cuối cùng. Bundler hiện đại giao kèm minify CSS theo mặc định, webpack 5 bao gồm css-minimizer-webpack-plugin (cssnano dưới mui mặc định, với cssoMinify, cleanCssMinify, esbuildMinify và lightningCssMinify đều có thể chọn); Vite dùng esbuild cho CSS theo mặc định và hỗ trợ Lightning CSS opt-in; Parcel dùng Lightning CSS; Next.js, Remix, Astro, SvelteKit và Nuxt đều đóng gói minify trong build production không cần lập trình viên can thiệp. Kết quả là cho bất cứ ai dùng pipeline build hiện đại, minify CSS đến tự động.
Nhưng không phải ai cũng dùng pipeline build. Rất nhiều site WordPress, trang HTML viết tay, site tĩnh Jekyll/Hugo/Eleventy không có toolchain JS, và dự án lẻ giao CSS chưa từng gần webpack. Cho những trường hợp đó, một trình minify trong trình duyệt là con đường ít ma sát nhất, dán CSS, sao kết quả, lưu vào triển khai.
Critical CSS
Một kỹ thuật bổ sung cần biết: critical CSS là việc xác định tập con style cần để render vùng thấy được phía trên "đường gấp", inline tập con đó trực tiếp vào khối <style> trong head của tài liệu, và defer phần còn lại của stylesheet thành tải không-chặn. Làm đúng, trang vẽ khung hình ban đầu ở chuyến đi mạng đầu tiên, không cần request riêng cho stylesheet bên ngoài. Filament Group dựng tooling kinh điển, Scott Jehl công bố loadCSS ngày 14 tháng 7 năm 2014, một tiện ích JavaScript nhỏ tải stylesheet bất đồng bộ bằng cách đặt thuộc tính media của nó về giá trị không khớp, rồi đảo về all sau khi tệp đã tải. Khuôn mẫu trở nên đủ chuẩn để các trình duyệt thêm <link rel="preload" as="style" onload="this.rel='stylesheet'"> như cách trực tiếp hơn để diễn đạt. Jason Miller (người tạo Preact) công bố Critters dưới GoogleChromeLabs năm 2018 như giải pháp thay thế nhanh hơn, thay vì chạy trình duyệt headless để soi trang đã render, Critters phân tích tĩnh. Repo Critters được lưu trữ năm 2024, fork được bảo trì tích cực nay sống dưới tên Beasties, dưới đội Nuxt. Tất cả công cụ này phụ thuộc vào việc CSS bên dưới được minify tốt, mỗi byte tiết kiệm trong stylesheet nguồn dội xuống thành inline critical nhỏ hơn.
Các hack di sản đã biến mất
Trình duyệt hiện đại đều phân tích CSS theo cùng đặc tả. Các hack lịch sử từng làm minify CSS rủi ro về cơ bản đã biến mất: hack * html nhắm IE6 bằng cách khai thác lỗi parser; hack gạch dưới _property: value nhắm IE6 và trước; *property: value (với * trước tên thuộc tính) nhắm IE7 và trước; comment điều kiện <!--[if IE 6]> cho phép phục vụ stylesheet khác cho phiên bản IE cụ thể, nhưng Microsoft bỏ tính năng đó trong IE10. IE11 đến cuối đời ngày 15 tháng 6 năm 2022 cho phần lớn phiên bản Windows 10 dùng phổ thông. Từ năm 2026, các hack này là tò mò lịch sử và một trình minify CSS không phải nghĩ về chúng nữa. Một trình minify hiện đại bỏ khoảng trắng giống nhau qua các trình duyệt và áp các biến đổi spec-định-nghĩa mô tả ở trên là an toàn.
Công cụ này làm gì (và không làm gì)
Công cụ này là một trình minify trong trình duyệt một-tệp, khoảng 30 dòng JavaScript. Nó tokenize literal chuỗi vào placeholder để các lượt tiếp theo không thể phá nội dung, bỏ comment /* ... */, gộp khoảng trắng quanh {, }, :, ;, ,, >, ~, +, bỏ dấu chấm phẩy cuối trước }, gộp chuỗi khoảng trắng thành một, rút gọn màu hex sáu chữ số thành ba chữ số khi mỗi cặp giống nhau, và bỏ đơn vị của giá trị không cho px, em, rem, %, pt, ex, ch, vw, vh, vmin, vmax. Nó không phân tích CSS thành AST, đó là một lượt regex. Nó không rút gọn longhand sang shorthand. Nó không gộp hay khử trùng selector. Nó không sắp xếp lại khai báo. Nó không chuyển rgb() sang hex hay tên màu sang hex. Nó không đưa từ khóa về chữ thường. Nó không giữ comment "quan trọng" /*!, mọi comment đều bị bỏ; nếu bạn có header giấy phép cần giữ, hãy dán lại sau khi minify. Nó không phát source map. Phạm vi trung thực: dán CSS từ trình soạn của bạn hoặc từ tay, lấy lại phiên bản đã trần thường nhỏ hơn 20-40% theo byte thô, và dùng nó như artifact triển khai nhanh cho site dựng tay. Cho dự án có pipeline build, hãy dùng cssnano hoặc Lightning CSS trong pipeline đó; cho cái không có, công cụ này gỡ ma sát.
Vì sao chỉ-trong-trình-duyệt quan trọng ở đây
Mọi trình minify CSS web có cùng lựa chọn kiến trúc: làm việc trên server, hoặc làm trong trình duyệt người dùng. Xử lý phía server đòi upload stylesheet qua mạng, nghĩa là một bản sao của CSS đó nằm trong log server, có thể trong cache CDN, có thể trong pipeline phân tích, có thể trong sao lưu. Cho phần lớn CSS, vô hại. Cho công cụ nội bộ, style sản phẩm chưa công bố, hoặc stylesheet chứa selector tiết lộ phân loại class nội bộ (.admin-panel-internal-debug-info), không. Ngay cả cho CSS site marketing thông thường, lập trình viên kiểm tra cái họ thực sự gửi qua mạng có thể hợp lý ưu tiên việc giữ công việc đang dở trên máy của mình. Một trình minify thuần dựa trên trình duyệt, JavaScript chạy trong tab và không bao giờ gọi mạng sau lần tải trang đầu, lách được vấn đề. Bạn có thể kiểm chứng: mở tab Network của DevTools, dán CSS, bấm Minify, và rình bất kỳ request đi ra. Sẽ không có. Tốt hơn nữa, ngắt internet (hoặc bật chế độ máy bay) sau khi trang đã tải và công cụ vẫn hoạt động, đó là bằng chứng thực nghiệm mạnh nhất rằng không gì được tải lên.
Câu hỏi thường gặp
CSS của tôi sẽ co lại bao nhiêu?
CSS định dạng tay có comment và thụt lề thường co lại 20-40% theo byte thô. CSS đã được biên dịch từ Sass/Less và định dạng nhẹ co ít hơn. CSS đã đi qua PostCSS hay Autoprefixer thường đã có comment tối thiểu và co ít nhất. Kích thước sau nén Brotli ở biên CDN sẽ siết hơn nữa, Brotli trên CSS đã minify vẫn tiết kiệm thêm 5-15% so với Brotli trên CSS không minify, tùy mức độ lặp của khoảng trắng gốc.
Đầu ra đã minify có phá thứ gì không?
Cho CSS thông thường, không, các biến đổi an toàn theo đặc tả. Hai trường hợp đáng tự kiểm tra: (1) giá trị không bên trong calc(), min(), max(), clamp() và thuộc tính tùy biến CSS không nên bị bỏ đơn vị vì các quy tắc số học có kiểu đòi đơn vị; lượt regex của công cụ này thận trọng nhưng nếu bạn có calc(0px + 10%) trong CSS, hãy xem đầu ra. (2) Nếu stylesheet có fallback thuộc tính trùng như display: flex; display: grid;, công cụ này giữ cả hai, nhưng các trình minify nâng cao như cssnano với preset advanced sẽ bỏ cái đầu. Nếu bạn dựa vào hành vi cascade riêng cho trình duyệt, hãy audit trước khi triển khai.
Có giữ header giấy phép không?
Không. Trình minify production tôn trọng quy ước rằng comment bắt đầu bằng /*! (với dấu chấm than) được giữ là "quan trọng", thường cho header bản quyền và thông báo giấy phép. Công cụ này bỏ mọi comment như nhau. Nếu bạn giao CSS cần header giấy phép (MIT, GPL, attribution nguồn BSD), hãy dán header thủ công trở lại đầu ra. Cho pipeline cần giữ tự động, hãy dùng cssnano hoặc Lightning CSS thay thế.
Có nên dùng nếu tôi đã có pipeline build?
Có lẽ không, bundler của bạn đã làm điều đó cho bạn. webpack 5 giao css-minimizer-webpack-plugin với cssnano dưới mui; Vite dùng esbuild cho minify CSS theo mặc định; Parcel dùng Lightning CSS. Công cụ này dành cho các trường hợp pipeline build của bạn không bao phủ: HTML viết tay, theme WordPress giao không có toolchain Node, trình sinh site tĩnh không bundle minify, tệp CSS lẻ cho template email hoặc demo nhanh. Cho những cái đó, công cụ paste-in trong trình duyệt là con đường ít ma sát.
Tệp của tôi có bị tải lên không?
Không. Trình minify là JavaScript chạy trong trình duyệt. CSS bạn dán không bao giờ đi qua mạng, hãy kiểm chứng trong tab Network của DevTools khi bạn bấm Minify, hoặc đặt trang offline sau khi đã tải xong và xác nhận công cụ vẫn hoạt động. Stylesheet nội bộ, style sản phẩm chưa công bố và CSS tiết lộ phân loại class nội bộ vẫn ở trên thiết bị của bạn.
Tôi có thể bỏ-minify đầu ra sau không?
Không hẳn, comment và khoảng trắng gốc đã đi mất, đó là mục đích. Nhưng bạn có thể định dạng CSS đã minify để nó đọc được lại. Pretty-printer như Prettier (với plugin CSS), lệnh Format Document tích hợp trong VS Code, hoặc bất cứ "trình làm đẹp CSS online" nào sẽ chèn lại thụt lề và xuống dòng. Chúng không thể khôi phục comment đã bỏ. Hãy luôn giữ nguồn không-minify trong version control như dạng kinh điển.
Công cụ liên quan
Bộ minify HTML
Minify HTML bằng cách loại bỏ comment, khoảng trắng và thuộc tính tùy chọn.
Bộ minify JavaScript
Minify JavaScript bằng cách loại bỏ comment và khoảng trắng để giảm kích thước.
Bộ tối ưu SVG
Tối ưu hóa và minify các tệp SVG bằng cách loại bỏ comment, metadata và khoảng trắng không cần thiết.