Cách tải CSS không đồng bộ


93

Tôi đang cố gắng loại bỏ 2 tệp CSS đang chặn hiển thị trên trang web của mình - chúng xuất hiện trên Google Page Speed ​​Insights. Tôi đã làm theo các phương pháp khác nhau, không phương pháp nào thành công. Nhưng, gần đây, tôi đã tìm thấy một bài đăng về Thinking Async và khi tôi áp dụng mã này: <script async src="https://third-party.com/resource.js"></script>nó đã loại bỏ được vấn đề.

Tuy nhiên, sau khi xuất bản, trang bị mất kiểu dáng. Tôi không quá chắc chắn về những gì đang xảy ra bởi vì mã hoạt động nhưng chính kiểu dáng sau khi tải lên không hoạt động. Đánh giá cao sự giúp đỡ của bạn với điều này. Cảm ơn


2
Bạn có đang áp dụng không đồng bộ cho kiểu hoặc tập lệnh không? Kiểu tải một thời gian sau khi bạn tải trang hoặc nó không bao giờ xuất hiện?
kamus

Tôi đã áp dụng thuộc tính async cho các kiểu và đặt chúng trong tiêu đề.
Paulina994,

2
Vấn đề với các kiểu là kết xuất sẽ được kích hoạt nếu bạn tải chúng muộn (ví dụ như trong phần nội dung) và không được phép trong các tiêu chuẩn (nhưng vì các trình duyệt rất tha thứ nên nó vẫn hoạt động). Nếu vấn đề là thời gian phản hồi chậm từ máy chủ của bên thứ ba, có lẽ bạn chỉ cần lưu trữ chúng trên máy chủ của mình?
Josef Engelfrost

Câu trả lời:


129

Mẹo để kích hoạt tải xuống biểu định kiểu không đồng bộ là sử dụng một <link>phần tử và đặt giá trị không hợp lệ cho thuộc tính media (tôi đang sử dụng media = "none", nhưng bất kỳ giá trị nào cũng được). Khi truy vấn phương tiện đánh giá là false, trình duyệt sẽ vẫn tải xuống biểu định kiểu, nhưng nó sẽ không đợi nội dung có sẵn trước khi hiển thị trang.

<link rel="stylesheet" href="css.css" media="none">

Sau khi tải xong biểu định kiểu, thuộc tính media phải được đặt thành giá trị hợp lệ để các quy tắc kiểu sẽ được áp dụng cho tài liệu. Sự kiện onload được sử dụng để chuyển thuộc tính media thành tất cả:

<link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'">

Phương pháp tải CSS này sẽ cung cấp nội dung có thể sử dụng cho khách truy cập nhanh hơn nhiều so với phương pháp tiêu chuẩn. CSS quan trọng vẫn có thể được phân phối với phương pháp chặn thông thường (hoặc bạn có thể nội tuyến nó để có hiệu suất cao nhất) và các kiểu không quan trọng có thể được tải xuống dần dần và áp dụng sau trong quá trình phân tích cú pháp / kết xuất.

Kỹ thuật này sử dụng JavaScript, nhưng bạn có thể phục vụ cho các trình duyệt không sử dụng JavaScript bằng cách gói các <link>phần tử chặn tương đương trong một <noscript>phần tử:

<link rel="stylesheet" href="css.css" media="none" onload="if(media!='all')media='all'"><noscript><link rel="stylesheet" href="css.css"></noscript>

Bạn có thể xem hoạt động trong www.itcha.edu.sv

nhập mô tả hình ảnh ở đây

Nguồn trong http://keithclark.co.uk/


Ok .. Tôi không biết rằng bạn có thể tham chiếu các thuộc tính phần tử trong các trình xử lý trên chỉ bằng cách nhắc đến tên của chúng. Tôi luôn nghĩ 'sự kiện' là ngoại lệ duy nhất.
Teemoh

1
Vậy làm cách nào để giữ cho trang của bạn không bị nhấp nháy khi nó hiển thị mọi thứ? Ngoài ra, bạn có các kiểu shell ứng dụng cốt lõi nội tuyến để trang của bạn có một số bố cục ban đầu thay vì hiển thị thứ gì đó Lynx sẽ tự hào không?
Chris Love

2
Có vẻ như vẫn làm việc cho tôi. Sau khi làm điều này, tôi biết còn nhận được cảnh báo trong PageSpeed ​​Insights cho tệp này.
AndyWarren

3
điều này đang làm việc cho tôi (08-07-2018). Và nó mang lại điểm số tốt trong thông tin chi tiết về tốc độ trang
abilash er

1
IMHO, câu trả lời mới hơn của jabachetta sử dụng "tải trước" , có thể là giải pháp được ưa thích hiện nay. Nếu ai có một lý do để nghĩ này trả lời là vẫn thích hợp hơn, xin vui lòng thêm một bình luận giải thích lý do tại sao. Liên kết lý tưởng đến một tài nguyên xác nhận lý do tại sao / khi nào thì cách tiếp cận này vẫn có thể thích hợp hơn. [Giả sử bạn sử dụng polyfill để hỗ trợ preloadtrên Firefox và trên các trình duyệt cũ hơn - xem liên kết trong nhận xét đầu tiên của câu trả lời đó].
ToolmakerSteve

111

Cập nhật năm 2020


Câu trả lời đơn giản (hỗ trợ trình duyệt đầy đủ):

<link rel="stylesheet" href="style.css" media="print" onload="this.media='all'">

Câu trả lời được lập thành văn bản (với tính năng tải trước tùy chọn và dự phòng đã tắt tập lệnh):

 <!-- Optional, if we want the stylesheet to get preloaded. Note that this line causes stylesheet to get downloaded, but not applied to the page. Use strategically — while preloading will push this resource up the priority list, it may cause more important resources to be pushed down the priority list. This may not be the desired effect for non-critical CSS, depending on other resources your app needs. -->
 <link rel="preload" href="style.css" as="style">

 <!-- Media type (print) doesn't match the current environment, so browser decides it's not that important and loads the stylesheet asynchronously (without delaying page rendering). On load, we change media type so that the stylesheet gets applied to screens. -->
 <link rel="stylesheet" href="style.css" media="print" onload="this.media='all'">

 <!-- Fallback that only gets inserted when JavaScript is disabled, in which case we can't load CSS asynchronously. -->
 <noscript><link rel="stylesheet" href="style.css"></noscript>

Kết hợp tải trước và không đồng bộ:

Nếu bạn cần CSS tải trước và không đồng bộ hóa, giải pháp này chỉ cần kết hợp hai dòng từ câu trả lời được ghi ở trên, làm cho nó gọn gàng hơn một chút. Nhưng điều này sẽ không hoạt động trong Firefox cho đến khi chúng hỗ trợ từ khóa tải trước . Và một lần nữa, như đã nêu chi tiết trong câu trả lời được ghi ở trên, việc tải trước có thể không thực sự có lợi.

<link href="style.css" rel="preload" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="style.css"></noscript>

Cân nhắc bổ sung:

Lưu ý rằng, nói chung, nếu bạn định tải CSS không đồng bộ, bạn thường nên nội tuyến CSS quan trọng , vì CSS là tài nguyên chặn hiển thị là có lý do .

Tín dụng cho nhóm filament cho nhiều giải pháp CSS không đồng bộ của họ.


3
Không có nhu cầu sử dụng loadCSS, các polyfill là đủ: github.com/filamentgroup/loadCSS/blob/master/src/...
nathan

1
Trạng thái thông số kỹ thuật của Preload cuối cùng là [Đề xuất ứng cử viên của W3C]. ( W3.org/TR/preload/… ) Firefox hỗ trợ nó, nhưng vẫn bị tắt theo mặc định; nhấp vào liên kết "được hỗ trợ rộng rãi" của answer để xem mô tả "Tôi có thể sử dụng" về cờ Firefox kiểm soát nó.
ToolmakerSteve

1
Câu trả lời được cập nhật để cung cấp giải pháp hỗ trợ trình duyệt đầy đủ, cùng với giải thích bổ sung.
jabacchetta

1
@jabacchetta bản cập nhật 2020 được đánh giá rất cao, cảm ơn bạn. Tôi đang tìm kiếm cụ thể các hướng dẫn được viết trong thời gian gần đây, nơi hỗ trợ trình duyệt thường tốt hơn. Rất nhiều thay đổi trong 3 năm trên web!
Brandito

Rõ ràng, nó là tốt hơn để onload="this.rel='stylesheet'; this.onload = null". Rõ ràng là cần thiết lập this.onloadđể nulltránh điều này được gọi hai lần trong một số trình duyệt.
Flimm

9

Sử dụng media="print"onload

Nhóm filament gần đây (tháng 7 năm 2019) đã xuất bản một bài báo đưa ra đề xuất mới nhất của họ về cách tải CSS không đồng bộ. Mặc dù họ là nhà phát triển của loadCSS thư viện Javascript phổ biến , nhưng họ thực sự đề xuất giải pháp không yêu cầu thư viện Javascript này:

<link
  rel="stylesheet"
  href="/path/to/my.css"
  media="print"
  onload="this.media='all'; this.onload = null"
>

Việc sử dụng media="print"sẽ cho trình duyệt biết không sử dụng biểu định kiểu này trên màn hình, mà trên bản in. Các trình duyệt thực sự tải xuống các bảng định kiểu in này, nhưng không đồng bộ, đó là những gì chúng tôi muốn. Chúng tôi cũng muốn biểu định kiểu được sử dụng sau khi nó được tải xuống và chúng tôi đã thiết lập onload="this.media='all'; this.onload = null". (Một số trình duyệt sẽ gọi onloadhai lần, để giải quyết vấn đề đó, chúng tôi cần phải thiết lập this.onload = null.) Nếu muốn, bạn có thể thêm <noscript>dự phòng cho những người dùng hiếm hoi chưa bật Javascript.

Các bài viết gốc là đáng đọc, vì nó đi vào chi tiết hơn tôi đang ở đây. Bài viết này trên csswizardry.com cũng rất đáng để đọc.


5

bạn có thể cố gắng lấy nó theo nhiều cách:

1. sử dụng media="bogus"và một <link>ở chân

<head>
    <!-- unimportant nonsense -->
    <link rel="stylesheet" href="style.css" media="bogus">
</head>
<body>
    <!-- other unimportant nonsense, such as content -->
    <link rel="stylesheet" href="style.css">
</body>

2. chèn DOM theo cách cũ

<script type="text/javascript">
(function(){
  var bsa = document.createElement('script');
     bsa.type = 'text/javascript';
     bsa.async = true;
     bsa.src = 'https://s3.buysellads.com/ac/bsa.js';
  (document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(bsa);
})();
</script>

3. nếu bạn có thể thử các plugin, bạn có thể thử loadCSS

<script>
  // include loadCSS here...
  function loadCSS( href, before, media ){ ... }
  // load a file
  loadCSS( "path/to/mystylesheet.css" );
</script>

3
Ví dụ 2 tải Javascript, nhưng câu hỏi là về tải CSS. Bạn có biết nếu ví dụ 2 cũng hoạt động cho CSS, nếu bạn thay đổi từ <script>thành <style rel=stylesheet>? (Chỉ cần tò mò tôi sẽ sử dụng. loadCSS(Tức là ví dụ của bạn 3) thay vào đó, nếu tôi cần phải tải CSS sau.)
KajMagnus

5

Hàm bên dưới sẽ tạo và thêm vào tài liệu tất cả các bảng định kiểu mà bạn muốn tải không đồng bộ. (Nhưng, nhờ có Event Listener, nó sẽ chỉ làm như vậy sau khi tất cả các tài nguyên khác của cửa sổ đã được tải xong.)

Xem phần sau:

function loadAsyncStyleSheets() {

    var asyncStyleSheets = [
    '/stylesheets/async-stylesheet-1.css',
    '/stylesheets/async-stylesheet-2.css'
    ];

    for (var i = 0; i < asyncStyleSheets.length; i++) {
        var link = document.createElement('link');
        link.setAttribute('rel', 'stylesheet');
        link.setAttribute('href', asyncStyleSheets[i]);
        document.head.appendChild(link);
    }
}

window.addEventListener('load', loadAsyncStyleSheets, false);

1
Có bất kỳ hạn chế nào của phương pháp này nếu chúng ta so sánh nó với phương pháp loadCSS không? Có vẻ như, mã cổ điển var newStyle = document.createElement("link"); newStyle.rel = "stylesheet"; newStyle.href = "stylesheet.css"; document.getElementsByTagName("head")[0].appendChild(newStyle);bên trong <script>thẻ trong nội dung trang hoạt động rất xuất sắc - ngay cả trong các trình duyệt cũ như MSIE8.
TecMan

2
@TecMan vâng, có. Như bạn có thể thấy, chức năng này hoạt động khi có window.loadsự kiện. Vì vậy, tải xuống bắt đầu khi mọi thứ được tải xuống. Không có may mắn ở đó. Bạn cần tải không chặn càng sớm càng tốt để bắt đầu.
Miloš Đakonović

5

Phương pháp tiếp cận tải CSS không đồng bộ

có một số cách để làm cho trình duyệt tải CSS không đồng bộ, mặc dù không có cách nào hoàn toàn đơn giản như bạn mong đợi.

<link rel="preload" href="mystyles.css" as="style" onload="this.rel='stylesheet'">

1

Nếu bạn cần tải liên kết CSS theo cách lập trình và không đồng bộ:

// https://www.filamentgroup.com/lab/load-css-simpler/
function loadCSS(href, position) {
  const link = document.createElement('link');
  link.media = 'print';
  link.rel = 'stylesheet';
  link.href = href;
  link.onload = () => { link.media = 'all'; };
  position.parentNode.insertBefore(link, position);
}

0

Nếu bạn có chính sách bảo mật nội dung nghiêm ngặt không cho phép câu trả lời của @ vladimir-salguero , bạn có thể sử dụng điều này (vui lòng ghi chú tập lệnh ):nonce

<script nonce="(your nonce)" async>
$(document).ready(function() {
    $('link[media="none"]').each(function(a, t) {
        var n = $(this).attr("data-async"),
            i = $(this);
        void 0 !== n && !1 !== n && ("true" == n || n) && i.attr("media", "all")
    })
});
</script>

Chỉ cần thêm những điều sau đây để tham khảo stylesheet của bạn: media="none" data-async="true". Đây là một ví dụ:

<link rel="stylesheet" href="../path/script.js" media="none" data-async="true" />

Ví dụ cho jQuery:

<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css" type="text/css" media="none" data-async="true" crossorigin="anonymous" /><noscript><link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css" type="text/css" /></noscript>

Tôi nghĩ rằng asyncthuộc tính bị bỏ qua, vì thẻ tập lệnh không có srcquyền tải không đồng bộ ... hay nó thực sự hữu ích ở đây? Ngoài ra, bạn có thể giải thích thêm một chút về giá trị nào được sử dụng như một nonce?
Philipp

0

Vui lòng cập nhật câu trả lời vì tất cả những điều trên không thể gây ấn tượng với google pagespeed Insights.

Theo Google, đây là cách bạn nên triển khai tải Css không đồng bộ

 < noscript id="deferred-styles" >
        < link rel="stylesheet" type="text/css" href="small.css"/ >
    < /noscript >

<script>
  var loadDeferredStyles = function() {
    var addStylesNode = document.getElementById("deferred-styles");
    var replacement = document.createElement("div");
    replacement.innerHTML = addStylesNode.textContent;
    document.body.appendChild(replacement)
    addStylesNode.parentElement.removeChild(addStylesNode);
  };
  var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
      window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
  if (raf) raf(function() { window.setTimeout(loadDeferredStyles, 0); });
  else window.addEventListener('load', loadDeferredStyles);
</script>

1
Có thể là dương tính giả (lỗi Tốc độ trang) nếu bạn đang sử dụng phương pháp tải trước từ khóa mà tôi đã đề cập. github.com/filamentgroup/loadCSS/issues/53
jabacchetta

1
CẬP NHẬT: Google đã ngừng sử dụng và sau đó ngừng hoạt động, PageSpeed ​​phiên bản 4 gặp sự cố này - đó là phiên bản mà mã không đồng bộ này được khuyến nghị. Mặc dù tôi chưa thử nghiệm trong PageSpeed ​​5 : với mô tả về cách họ kiểm tra hiện tại và sự hỗ trợ của họ cho thẻ "tải trước" của "liên kết", câu trả lời của jabachetta có thể là câu trả lời tốt hơn bây giờ cho Google.
ToolmakerSteve

1
@ToolmakerSteve Có Câu trả lời này cần được kiểm duyệt thường xuyên. Nhưng mã này vẫn hoạt động để giúp bạn đạt 100 Tốc độ trang.
kaushik gandhi,

0

Tôi đã thử sử dụng:

<link rel="preload stylesheet" href="mystyles.css" as="style">

Nó hoạt động tốt, nhưng nó cũng làm tăng sự thay đổi bố cục tích lũy vì khi chúng ta sử dụng rel = "preload", nó chỉ tải xuống css, không áp dụng ngay lập tức.

Ví dụ khi DOM tải một danh sách chứa các thẻ ul, li, mặc định có một dấu đầu dòng trước thẻ li, sau đó CSS ​​áp dụng để tôi loại bỏ các dấu đầu dòng này thành các kiểu tùy chỉnh cho danh sách. Vì vậy, sự thay đổi bố cục tích lũy đang xảy ra ở đây.

Có giải pháp nào cho điều đó không?


0

Sử dụng rel="preload"để làm cho nó tải xuống một cách độc lập, sau đó sử dụng onload="this.rel='stylesheet'"để áp dụng nó vào biểu định kiểu ( as="style"cần phải áp dụng nó vào biểu định kiểu nếu onloadkhông sẽ không hoạt động)

<link rel="preload" as="style" type="text/css" href="mystyles.css" onload="this.rel='stylesheet'">
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.