CDN이 실패 할 경우 로컬 스타일 시트 (스크립트 아님)로 대체하는 방법


108

CDN의 jQuery Mobile 스타일 시트에 연결 중이며 CDN이 실패 할 경우 스타일 시트의 로컬 버전으로 돌아가고 싶습니다. 스크립트의 경우 솔루션은 잘 알려져 있습니다.

<!-- Load jQuery and jQuery mobile with fall back to local server -->
<script src="http://code.jquery.com/jquery-1.6.3.min.js"></script>
<script type="text/javascript">
  if (typeof jQuery == 'undefined') {
    document.write(unescape("%3Cscript src='jquery-1.6.3.min.js'%3E"));
  }
</script>

스타일 시트에 대해 비슷한 작업을하고 싶습니다.

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css" />

스크립트를 링크 할 때 브라우저가 스크립트를로드 할 때와 같은 방식으로 차단하는지 여부를 확신 할 수 없기 때문에 비슷한 접근 방식을 얻을 수 있는지 확실하지 않습니다 (스크립트 태그에 스타일 시트를로드 한 다음 페이지에 삽입)?

그래서 내 질문은 : CDN이 실패하면 스타일 시트가 로컬로로드되는지 어떻게 확인합니까?


2
이것이 가능한지 알고 싶습니다. CDN이 다운되는 것이 정말 걱정된다면 로컬 호스팅을 사용합니다.
Fosco 2011 년

2
@Stefan Kendall, 올바른 진술은 그의 사이트가 CDN보다 다운 될 가능성이 높다는 것입니다
Shawn Mclean 2011 년

답변:


63

브라우저 간 테스트를 거치지 않았지만 이것이 작동 할 것이라고 생각합니다. 하지만 jquery를로드 한 후에야합니다. 그렇지 않으면 일반 Javascript로 다시 작성해야합니다.

<script type="text/javascript">
$.each(document.styleSheets, function(i,sheet){
  if(sheet.href=='http://code.jquery.com/mobile/1.0b3/jquery.mobile-1.0b3.min.css') {
    var rules = sheet.rules ? sheet.rules : sheet.cssRules;
    if (rules.length == 0) {
      $('<link rel="stylesheet" type="text/css" href="path/to/local/jquery.mobile-1.0b3.min.css" />').appendTo('head');
    }
 }
})
</script>

좋은 해결책, 해결되지 않는 한 가지 문제는 CDN이로드하기에 너무 느린 경우입니다 ... 일종의 시간 초과일까요?
GeorgeU 2011 년

2
들어 code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css , 나는 제대로로드 비록, 규칙 = 널 (null)을 얻는다. Chrome 26을 사용하고 있는데 스크립트가 도메인 간이기 때문이라고 생각합니까?
simplfuzz

8
이 솔루션은 정말 예를 들어, 모든 CDN 서비스 / 스타일 시트가 작동하지 않습니다 CSSStyleSheet모든 bootstrapcdn.com에서 오는 비어있는 JS 객체 rulescssRules브라우저 (크롬 31)의 필드. UPD : 실제로 도메인 간 문제 일 수 있으며 답변의 CSS 파일도 저에게 작동하지 않습니다.
Maksim Vi.

3
onerror이벤트를 이용한 좋은 솔루션 입니다. stackoverflow.com/questions/30546795/...
화학 프로그래머에게

2
다른 도메인에서로드 된 CSS에서 작동합니까? 아니, 당신은 열거 할 수 없습니다 .rules/ .cssRules외부 스타일 시트에 대한. jsfiddle.net/E6yYN/13
살만

29

질문은 스타일 시트가로드되었는지 여부를 감지하는 것입니다. 한 가지 가능한 접근 방식은 다음과 같습니다.

1) CSS 파일 끝에 다음과 같은 특수 규칙을 추가합니다.

#foo { display: none !important; }

2) HTML에 해당 div를 추가합니다.

<div id="foo"></div>

3) 문서가 준비되면 #foo표시 여부를 확인합니다 . 스타일 시트가로드 된 경우 표시되지 않습니다.

여기 데모 -jquery-ui 부드러움 테마를로드합니다. 스타일 시트에 규칙이 추가되지 않습니다.


42
영리한 솔루션을 위해 +1. 유일한 문제는 일반적으로 누군가의 CDN에서 호스팅되는 스타일 시트의 끝에 행을 추가 할 수 없다는 것입니다
Jannie Theunissen

2
안타깝게도 CDN 파일에 자체 클래스를 입력 할 수 없습니다. 이미 존재하는 것을 활용하려고 노력할 수 있습니다.
Ahamed

1
나는 이것을 많이 좋아합니다. 감사합니다. 정말 강력합니다. 분명히 CDN 스타일 시트를 조작 할 수는 없지만 어떤 클래스가 사용되고 있는지 알고 있으므로 코드가 보이는지 확인하기 위해 코드를 수정했습니다. 정말 영리합니다. :)
Nosnibor

3
NB : 당신은하지 않습니다 정말 외부 CSS에 새 규칙을 추가해야합니다. 동작이 알려진 기존 규칙을 사용하십시오. 내 데모에서 요소를 숨길 것으로 예상되는 ui-helper-hidden 클래스를 사용하고 페이지로드시 요소가 숨겨 지는지 확인합니다.
살만

28

css 및 jQuery에 대해 동일한 CDN을 사용한다고 가정하면 한 번의 테스트를 수행하고 모두 잡는 것이 어떻습니까?

<link href="//ajax.googleapis.com/ajax/libs/jqueryui/1/themes/start/jquery-ui.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script type="text/javascript">
    if (typeof jQuery == 'undefined') {
        document.write(unescape('%3Clink rel="stylesheet" type="text/css" href="../../Content/jquery-ui-1.8.16.custom.css" /%3E'));
        document.write(unescape('%3Cscript type="text/javascript" src="/jQuery/jquery-1.6.4.min.js" %3E%3C/script%3E'));
        document.write(unescape('%3Cscript type="text/javascript" src="/jQuery/jquery-ui-1.8.16.custom.min.js" %3E%3C/script%3E'));
    }
</script>

1
이스케이프 처리되지 않은 문자열을 처음 사용할 때 어떤 문제가 있는지 물어봐도 document.write("<script type='text/javascript' src='path/to/file.js'>")될까요?
Jack Tuck 2015 년

2
@JackTuck : 파서는 <script>JS 문자열 내부와 외부에서 찾은 문자열을 구분할 수 없습니다 . 이것이 일반적으로 <\/script>CDN 대체 용 태그를 작성할 때도 볼 수있는 이유 입니다.
Brad Christie

6
-1- why not just do one test and catch it all?하나는 실패하고 다른 하나는 성공하는 백만 가지 이유가 있기 때문입니다.
Flimzy 2015-06-30

7

이 기사는 부트 스트랩 CSS http://eddmann.com/posts/providing-local-js-and-css-resources-for-cdn-fallbacks/에 대한 몇 가지 솔루션을 제안합니다 .

또는 이것은 fontawesome에서 작동합니다.

<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<script>
    (function($){
        var $span = $('<span class="fa" style="display:none"></span>').appendTo('body');
        if ($span.css('fontFamily') !== 'FontAwesome' ) {
            // Fallback Link
            $('head').append('<link href="https://stackoverflow.com/css/font-awesome.min.css" rel="stylesheet">');
        }
        $span.remove();
    })(jQuery);
</script>

Font Awesome 5와 함께 사용하려는 사람들을 위해 'FontAwesome'(if 절에서)을 'Font Awesome 5 Free'(무료 글꼴을 사용하는 경우)로 변경하고 싶을 것입니다. 그렇지 않으면 제대로 작동합니다.
Jason Clark

4

에서 스타일 시트가 있는지 테스트 할 수 있습니다document.styleSheets .

var rules = [];
if (document.styleSheets[1].cssRules)
    rules = document.styleSheets[i].cssRules
else if (document.styleSheets[i].rules)
    rule= document.styleSheets[i].rules

사용중인 CSS 파일에 특정한 것을 테스트하십시오.


4

이를 onerror위해 사용할 수 있습니다 .

<link rel="stylesheet" href="cdn.css" onerror="this.onerror=null;this.href='local.css';" />

그만큼 this.onerror=null; 경우에 자기를 사용할 수없는 대체를 무한 루프를 방지하는 것입니다. 그러나 여러 폴백을 갖는 데 사용될 수도 있습니다.

그러나 이것은 현재 Firefox 및 Chrome에서만 작동합니다.


3

다음은 katy lavallee의 답변에 대한 확장입니다. 변수 충돌을 방지하기 위해 모든 것을 자체 실행 함수 구문으로 래핑했습니다. 또한 스크립트를 단일 링크에 대해 비 특정 적으로 만들었습니다. IE, 이제 "data-fallback"url 속성이있는 모든 스타일 시트 링크가 자동으로 구문 분석됩니다. 이전과 같이이 스크립트에 URL을 하드 코딩 할 필요가 없습니다. 이는 <head>요소 의 끝이 아닌 끝에서 실행되어야합니다 . <body>그렇지 않으면 FOUC 가 발생할 수 있습니다 .

http://jsfiddle.net/skibulk/jnfgyrLt/

<link rel="stylesheet" type="text/css" href="broken-link.css" data-fallback="broken-link2.css">

.

(function($){
    var links = {};

    $( "link[data-fallback]" ).each( function( index, link ) {
        links[link.href] = link;
    });

    $.each( document.styleSheets, function(index, sheet) {
        if(links[sheet.href]) {
            var rules = sheet.rules ? sheet.rules : sheet.cssRules;
            if (rules.length == 0) {
                link = $(links[sheet.href]);
                link.attr( 'href', link.attr("data-fallback") );
            }
        }
    });
})(jQuery);

1
캡슐화를 좋아하지만 일반적으로 cross-domain 스타일 시트에 대해 sheet.rules를 검사 할 수 없습니다. 이 일반적인 아이디어를 계속 사용할 수 있지만 다른 검사를 수행해야합니다.
John Vinopal 2015 년

함께 document.styleSheets[i].ownerNode.dataset당신은 액세스 할 수있는 <link data-* />속성
의 Alwin 케슬러

2

CDN이 실패 할 경우 CSS를로드하기 위해이 자바 스크립트 경로로 이동 하시겠습니까?

성능에 미치는 영향을 모두 생각하지는 않았지만 CSS가로드되는시기를 제어 할 수 없게되며 일반적으로 페이지로드 성능에 대해 CSS가 HTML 이후에 가장 먼저 다운로드하려는 것입니다.

인프라 수준에서이를 처리하지 않는 이유는 무엇입니까? 자신의 도메인 이름을 CDN에 매핑하고, 짧은 TTL을 제공하고, CDN의 파일을 모니터링 (예 : Watchmouse 또는 기타 사용)하고, CDN이 실패하면 DNS를 백업 사이트로 변경합니다.

도움이 될 수있는 다른 옵션은 정적 콘텐츠에 대한 "영원히 캐시"이지만 브라우저가이를 물론 유지하거나 앱 캐시를 사용한다는 보장은 없습니다.

실제로 누군가가 상단에서 말했듯이 CDN이 신뢰할 수 없다면 새 CDN을 얻으십시오.

앤디


7
CDN은 신뢰할 수 있지만 개발 환경은 인터넷 연결이 아닙니다.)
icebreaker

1

다음 기능을 살펴보십시오.

$.ajax({
    url:'CSS URL HERE',
    type:'HEAD',
    error: function()
    {
        AddLocalCss();
    },
    success: function()
    {
        //file exists
    }
});

다음은 바닐라 JavaScript 버전입니다.

function UrlExists(url)
{
    var http = new XMLHttpRequest();
    http.open('HEAD', url, false);
    http.send();
    return http.status!=404;
}
if (!UrlExists('CSS URL HERE') {
AddLocalCss();
}

이제 실제 기능 :

function AddLocalCss(){
document.write('<link rel="stylesheet" type="text/css" href=" LOCAL CSS URL HERE">')
}

AddLocalCss가 헤드에서 호출되는지 확인하십시오.

이 답변에 설명 된 다음 방법 중 하나를 사용할 수도 있습니다 .

AJAX를 사용하여로드

$.get(myStylesLocation, function(css)
{
   $('<style type="text/css"></style>')
      .html(css)
      .appendTo("head");
});

동적 생성을 사용하여로드

$('<link rel="stylesheet" type="text/css" href="'+myStylesLocation+'" >')
   .appendTo("head");
Load using dynamically-created <style>

$('<style type="text/css"></style>')
    .html('@import url("' + myStylesLocation + '")')
    .appendTo("head");

또는

$('<style type="text/css">@import url("' + myStylesLocation + '")</style>')
    .appendTo("head");

예, 적어도 최신 브라우저에서는 IE6에 대해 잘 모르겠습니다.

전체를 다운로드하는 대신 확인하는 방법이 있습니까?
Shawn Mclean 2011 년

OP 요청을 수행하는 유일한 이유는 과도한 네트워크 트래픽을 피하는 것입니다. 이로 인해 과도한 네트워크 트래픽이 발생합니다.
Stefan Kendall 2011 년

@stefan Kendall : 아니요, 파일이로드되었는지 확인하고 싶지 않은 이유도 아닙니다.

이것이 유일한 문제라면 CDN을 사용하지 않을 것입니다. 헤더 만 테스트하는 것이 더 좋지만 대부분의 CDN과 브라우저가 XSS를 허용하지 않을 것이라고 확신합니다.
Stefan Kendall 2011 년

-1

나는 아마도 yepnope.js와 같은 것을 사용할 것입니다.

yepnope([{
  load: 'http:/­/ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js',
  complete: function () {
    if (!window.jQuery) {
      yepnope('local/jquery.min.js');
    }
  }
}]);

Readme 에서 가져 왔습니다 .


10
@BenSchwarz, 그렇다고해서 질문에 답할 수없는 관련없는 코드를 붙여 넣을 수 있다는 의미는 아닙니다.
AlicanC 2013

-8
//(load your cdn lib here first)

<script>window.jQuery || document.write("<script src='//me.com/path/jquery-1.x.min.js'>\x3C/script>")</script>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.