CSS를 비동기 적으로로드하는 방법


92

내 사이트에서 렌더링을 차단하는 2 개의 CSS 파일을 제거하려고합니다.이 파일은 Google Page Speed ​​Insights에 표시됩니다. 나는 다른 방법을 따랐지만 어느 것도 성공하지 못했습니다. 하지만 최근에 Thinking Async 에 대한 게시물을 찾았고이 코드를 적용했을 때 <script async src="https://third-party.com/resource.js"></script>문제가 해결되었습니다.

그러나 게시 후 페이지의 스타일이 손실되었습니다. 코드가 작동하기 때문에 무슨 일이 일어나고 있는지 잘 모르겠지만 작동하지 않는 업로드 후 스타일링입니다. 도움을 주시면 감사하겠습니다. 감사


2
스타일이나 스크립트에 비동기를 적용하고 있습니까? 스타일이 페이지를로드 한 후 얼마 동안로드되거나 나타나지 않습니까?
kamus

스타일에 비동기 속성을 적용하고 헤더에 배치했습니다.
Paulina994

2
스타일의 문제는 늦게로드하면 (예 : 본문에서) 다시 렌더링이 트리거되고 표준에서 허용되지 않는다는 것입니다 (하지만 브라우저가 매우 용서하기 때문에 어쨌든 작동합니다). 문제가 타사 서버의 느린 응답 시간 인 경우 서버에서 호스팅 할 수 있습니까?
Josef Engelfrost 2015 년

답변:


129

비동기 스타일 시트 다운로드를 트리거하는 비결은 <link>요소 를 사용 하고 미디어 속성에 대해 잘못된 값을 설정하는 것입니다 (나는 media = "none"을 사용하고 있지만 모든 값이 사용됩니다). 미디어 쿼리가 false로 평가되면 브라우저는 여전히 스타일 시트를 다운로드하지만 페이지를 렌더링하기 전에 콘텐츠를 사용할 수있을 때까지 기다리지 않습니다.

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

스타일 시트 다운로드가 완료되면 미디어 속성을 유효한 값으로 설정해야 스타일 규칙이 문서에 적용됩니다. onload 이벤트는 미디어 속성을 모두로 전환하는 데 사용됩니다.

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

이 CSS로드 방법은 표준 접근 방식보다 훨씬 빠르게 방문자에게 유용한 콘텐츠를 제공합니다. 중요한 CSS는 여전히 일반적인 차단 방식으로 제공 될 수 있으며 (또는 궁극적 인 성능을 위해 인라인 할 수 있음) 중요하지 않은 스타일은 나중에 파싱 / 렌더링 프로세스에서 점진적으로 다운로드하여 적용 할 수 있습니다.

이 기술은 자바 스크립트를 사용하지만 <link>요소에 동등한 차단 요소를 래핑하여 자바 스크립트가 아닌 브라우저를 수용 할 수 있습니다 <noscript>.

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

www.itcha.edu.sv 에서 작업을 볼 수 있습니다.

여기에 이미지 설명 입력

http://keithclark.co.uk/의 출처


Ok .. 이름 만 언급하는 것만으로 on-handler의 요소 속성을 참조 할 수 있다는 것을 몰랐습니다. 나는 항상 '이벤트'가 유일한 예외라고 생각했습니다.
Teemoh

1
그렇다면 모든 것을 다시 렌더링 할 때 페이지가 번쩍이지 않게하려면 어떻게해야합니까? 또한 핵심 앱 셸 스타일을 인라인하여 페이지에 Lynx가 자랑스럽게 생각하는 것을 렌더링하는 대신 초기 레이아웃이 있습니까?
Chris Love

2
여전히 나를 위해 일하는 것 같습니다. 이렇게하면이 파일에 대해 PageSpeed ​​Insights에서 더 이상 경고가 표시된다는 것을 알고 있습니다.
AndyWarren

3
이것은 나를 위해 일하고 있습니다 (2018 년 7 월 8 일). 그리고 페이지 속도 통찰력에 좋은 점수를주고
abilash 어

1
"preload"를 사용하는 jabachetta의 최신 답변 인 IMHO 가 현재 선호되는 솔루션 일 것입니다. 답변이 여전히 낫다고 생각하는 이유가 있다면 그 이유를 설명하는 의견을 추가하십시오. 이 접근 방식이 여전히 바람직한 이유 /시기를 확인하는 리소스에 연결하는 것이 이상적입니다. [ preloadFirefox 및 이전 브라우저에서 지원하기 위해 polyfill을 사용한다고 가정합니다 . 해당 답변의 첫 번째 댓글에있는 링크 참조].
ToolmakerSteve

109

2020 업데이트


간단한 대답 (전체 브라우저 지원) :

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

문서화 된 답변 (선택적 사전로드 및 스크립트 비활성화 대체 포함) :

 <!-- 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>

사전로드 및 비동기 결합 :

미리로드 된 비동기 CSS가 필요한 경우이 솔루션은 위의 문서화 된 답변에서 두 줄을 결합하여 약간 더 깔끔하게 만듭니다. 그러나 이것은 preload 키워드 를 지원할 때까지 Firefox에서 작동하지 않습니다 . 그리고 위의 문서화 된 답변에서 자세히 설명했듯이 사전로드는 실제로 유익하지 않을 수 있습니다.

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

추가 고려 사항 :

비동기로드 CSS로 이동하는 경우, 일반적으로, 그 주, 그것은 일반적으로 권장 당신 인라인 중요한 CSS , CSS는 렌더링 차단 자원이기 때문에 이유가가 .

많은 비동기 CSS 솔루션에 대한 필라멘트 그룹의 공로 .


3
loadCSS를 사용할 필요가 없습니다. polyfill이면 충분합니다. github.com/filamentgroup/loadCSS/blob/master/src/…
nathan

1
Preload의 사양 상태는 마침내 [W3C Candidate Recommendation]입니다. ( w3.org/TR/preload/… ) Firefox는이를 지원하지만 기본적으로 비활성화되어 있습니다. 답변을 제어하는 ​​Firefox 플래그의 "사용할 수 있습니까?"에 대한 답변의 "광범위하게 지원됨"링크를 클릭하십시오.
ToolmakerSteve

1
추가 설명과 함께 전체 브라우저 지원에 대한 솔루션을 제공하기 위해 답변이 업데이트되었습니다.
jabacchetta

1
@jabacchetta 2020 업데이트는 대단히 감사합니다. 브라우저 지원이 일반적으로 더 나은 최근에 작성된 지침을 구체적 으로 찾고있었습니다 . 3 년 동안 웹에서 많은 변화가있었습니다!
Brandito

분명히 onload="this.rel='stylesheet'; this.onload = null". 분명히 일부 브라우저에서 두 번 호출되지 않도록 설정 this.onload해야 null합니다.
Flimm

9

media="print"및 사용onload

필라멘트 그룹은 최근 (2019 년 7 월) CSS를 비동기식으로로드하는 방법에 대한 최신 권장 사항을 제공 하는 기사게시했습니다 . 인기있는 Javascript 라이브러리 loadCSS 의 개발자이지만 실제로 Javascript 라이브러리가 필요하지 않은이 솔루션을 권장합니다.

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

을 사용 media="print"하면 화면에서이 스타일 시트를 사용하지 않고 인쇄 할 때 브라우저에 표시됩니다. 브라우저는 실제로 이러한 인쇄 스타일 시트를 다운로드하지만 비동기식으로 다운로드합니다. 또한 스타일 시트가 다운로드 된 후 사용되기를 원하며이를 위해 onload="this.media='all'; this.onload = null". (일부 브라우저는 onload두 번 호출 하므로이 문제를 해결하려면을 설정해야합니다 this.onload = null.) 원하는 경우 <noscript>Javascript를 활성화하지 않은 드문 사용자를 위해 대체를 추가 할 수 있습니다 .

원래 기사는 내가 여기보다 더 세부 사항으로 간다, 읽기 가치가있다. csswizardry.com의이 기사 도 읽을 가치가 있습니다.


5

여러 가지 방법으로 얻을 수 있습니다.

1.Using media="bogus"<link>발에

<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. 기존 방식으로 DOM 삽입

<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.If는 당신이 시도 할 수 loadCSS을

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

3
예제 2는 자바 스크립트를로드하지만 문제는 CSS로드에 관한 것입니다. 에서 <script>로 변경하면 예제 2가 CSS에서도 작동하는지 알고 <style rel=stylesheet>있습니까? (그냥 궁금해서 내가 사용하려고 해요. loadCSS(즉, 귀하의 예제 3) 대신에, 나중에 부하 CSS에 필요합니다.)
KajMagnus

5

아래 함수는 비동기 적으로로드하려는 모든 스타일 시트를 작성하고 문서에 추가합니다. (그러나, 덕분에 Event Listener모든 창의 다른 리소스가로드 된 후에 만 ​​그렇게 할 것입니다.)

다음을 참조하십시오.

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
loadCSS 접근 방식과 비교하면이 방법의 단점이 있습니까? 페이지 본문 var newStyle = document.createElement("link"); newStyle.rel = "stylesheet"; newStyle.href = "stylesheet.css"; document.getElementsByTagName("head")[0].appendChild(newStyle);<script>태그 내부 의 고전적인 코드 는 MSIE8과 같은 오래된 브라우저에서도 훌륭하게 작동합니다.
TecMan

2
@TecMan 네, 있습니다. 보시다시피,이 함수는 window.load이벤트 에 대한 작업을 수행합니다 . 따라서 모든 것이 다운로드되면 다운로드가 시작됩니다. 거기에 행운이 없습니다. 시작하려면 가능한 한 빨리 비 차단로드가 필요합니다.
Miloš Đakonović

5

비동기 CSS 로딩 방식

브라우저가 CSS를 비동기 적으로로드하도록 만드는 방법에는 여러 가지가 있지만 예상만큼 간단한 방법은 없습니다.

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

1

프로그래밍 방식 및 비동기식으로 CSS 링크를로드해야하는 경우 :

// 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

@ vladimir-salguero답변을 허용하지 않는 엄격한 콘텐츠 보안 정책이있는 경우 다음을 사용할 수 있습니다 (스크립트를 기록해 두십시오 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>

스타일 시트 참조에 다음을 추가하십시오 media="none" data-async="true".. 예를 들면 다음과 같습니다.

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

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>

async스크립트 태그에 src비동기 적으로로드 할 필요가 없기 때문에 속성이 무시 되었다고 생각합니다 ... 아니면 여기서 정말 유용합니까? 또한으로 사용할 값에 대해 좀 더 자세히 설명 할 수 nonce있습니까?
필립

0

위의 모든 내용이 Google pagespeed 통찰력에 깊은 인상을주지 못하므로 답변을 업데이트하십시오.

Google 에 따르면 이것이 CSS의 비동기 로딩을 구현하는 방법입니다.

 < 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
앞서 언급 한 사전로드 키워드 접근 방식을 사용하는 경우 오탐 (PageSpeed ​​버그) 일 가능성이 있습니다. github.com/filamentgroup/loadCSS/issues/53
jabacchetta

1
업데이트 : Google은이 문제가있는 PageSpeed ​​버전 4를 지원 중단 한 다음 종료했습니다.이 버전은이 비동기 코드가 권장되는 버전입니다. PageSpeed ​​5에서 테스트하지는 않았지만 지금 테스트하는 방법에 대한 설명과 "link"의 "preload"태그에 대한 지원을 고려할 때 jabachetta의 대답 이 이제 더 나은 대답 일 가능성이 높습니다.
ToolmakerSteve

1
@ToolmakerSteve 예이 답변은 자주 검토되어야합니다. 그러나이 코드는 여전히 Page Speed에서 100 점을 얻습니다.
kaushik gandhi

0

나는 사용하려고 :

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

잘 작동하지만 rel = "preload"를 사용할 때 즉시 적용되지 않고 css 만 다운로드하기 때문에 누적 레이아웃 이동이 발생합니다.

DOM이 목록을로드 할 때 ul, li 태그가 포함되어 있고 기본적으로 li 태그 앞에 글 머리 기호가있는 경우 CSS가 적용되어 나열을 위해 이러한 글 머리 기호를 제거했습니다. 그래서 여기서 누적 레이아웃 이동이 일어나고 있습니다.

그것에 대한 해결책이 있습니까?


0

사용 rel="preload"후 사용이 독립적으로 다운로드 할 수 있습니다 onload="this.rel='stylesheet'"(스타일 시트에 적용 할 as="style"다른 스타일에 적용하는 것이 필요하다 onload하지 않습니다 일)

<link rel="preload" as="style" type="text/css" href="mystyles.css" onload="this.rel='stylesheet'">
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.