Google의 호스팅 jQuery를 사용하는 가장 좋은 방법이지만 Google 실패의 호스팅 된 라이브러리로 돌아갑니다.

StackOverflow https://stackoverflow.com/questions/1014203

문제

로드하려는 좋은 방법은 무엇입니까 Google에서 호스팅 된 jQuery (또는 다른 Google을 호스팅 한 Libs) 그러나 Google 시도가 실패하면 jQuery 사본을로드합니까?

나는 구글이 벗겨지고 있다고 말하는 것이 아니다. Google 사본이 차단되는 경우가 있습니다 (예 :이란에서는 분명히).

타이머를 설정하고 jQuery 객체를 확인합니까?

두 사본이 나오는 위험은 무엇입니까?

"Google One을 사용하십시오"또는 "자신의 것을 사용하십시오"와 같은 답을 찾고 있지 않습니다. 나는 그 주장을 이해합니다. 또한 사용자가 Google 버전을 캐시 할 가능성이 있음을 이해합니다. 나는 일반적으로 클라우드의 폴백에 대해 생각하고 있습니다.


편집 :이 부분이 추가되었습니다 ...

Google은 Google.Load를 사용하여 AJAX 라이브러리를로드하고 완료되면 콜백을 수행하는 것을 제안하기 때문에이 문제를 직렬화하는 열쇠인지 궁금합니다.

나는 그것이 조금 미쳤다는 것을 안다. 나는 그것이 신뢰할 수있는 방식으로 할 수 있는지 알아 내려고 노력하고 있습니다.


업데이트 : JQuery는 이제 Microsoft의 CDN에서 호스팅되었습니다.

http://www.asp.net/ajax/cdn/

도움이 되었습니까?

해결책

다음과 같이 달성 할 수 있습니다.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script>
   window.jQuery || document.write('<script src="/path/to/your/jquery"><\/script>');
</script>

이것은 귀하의 페이지에 있어야합니다 <head> 그리고 모든 jQuery Ready 이벤트 처리기는 <body> 오류를 피하기 위해 (바보는 아니지만!).

또 하나의 이유 ~ 아니다 Google 호스팅 된 jQuery 사용 일부 국가에서는 Google의 도메인 이름이 금지된다는 것입니다.

다른 팁

이 작업을 수행하는 가장 쉽고 깨끗한 방법 :

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="path/to/your/jquery"><\/script>')</script>

이것은 나에게 효과가있는 것 같습니다.

<html>
<head>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
// has the google object loaded?
if (window.google && window.google.load) {
    google.load("jquery", "1.3.2");
} else {
    document.write('<script type="text/javascript" src="http://joecrawford.com/jquery-1.3.2.min.js"><\/script>');
}
window.onload = function() {
    $('#test').css({'border':'2px solid #f00'});
};
</script>
</head>
<body>
    <p id="test">hello jQuery</p>
</body>
</html>

그것이 작동하는 방식은 사용하는 것입니다 google 그 부르는 대상 http://www.google.com/jsapi 로드 window 물체. 해당 객체가 없으면 Google에 대한 액세스가 실패한다고 가정합니다. 이 경우를 사용하여 로컬 사본을로드합니다. document.write. (이 경우 내 자신의 서버를 사용하고 있습니다. 테스트하기 위해 직접 사용하십시오).

나는 또한 존재를 테스트합니다 window.google.load - 나도 할 수 있습니다 typeof 사물이 적절한 대상이나 기능인지 확인하십시오. 그러나 나는 이것이 트릭을한다고 생각합니다.

테스트중인 전체 HTML 페이지를 게시 한 이후 코드 강조 표시가 실패한 것처럼 보이므로로드 로직이 있습니다.

if (window.google && window.google.load) {
    google.load("jquery", "1.3.2");
} else {
    document.write('<script type="text/javascript" src="http://joecrawford.com/jquery-1.3.2.min.js"><\/script>');
}

내가 말해야하지만, 이것이 귀하의 사이트 방문자에게 우려라면 당신은 Google Ajax 라이브러리 API 조금도.

재미있는 사실: 처음에는 다양한 버전으로 이것에 대한 Catch 블록을 사용하려고 시도했지만 이것만큼 깨끗한 조합을 찾을 수 없었습니다. 나는이 아이디어의 다른 구현을 순전히 운동으로보고 싶어합니다.

사이트에 ModernIzr.js가 포함 된 경우 내장 된 yepnope.js를 사용하여 스크립트를 비동기 적으로로드 할 수 있습니다.

Modernizr.load([{
    load : '//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'
},{
    test : window.jQuery,
    nope : 'path/to/local/jquery-1.7.2.min.js',
    both : ['myscript.js', 'another-script.js'],
    complete : function () {
        MyApp.init();
    }
}]);

이것은 Google-CDN에서 jQuery를로드합니다. 그 후 jQuery가 성공적으로로드 된 경우 확인됩니다. 그렇지 않은 경우 ( "Nope") 로컬 버전이로드됩니다. 또한 귀하의 개인 스크립트가로드됩니다. "둘 다"는로드 프로세스가 테스트 결과와 독립적으로 초기화되었음을 나타냅니다.

모든로드 프로세스가 완료되면 'myapp.init'의 경우 함수가 실행됩니다.

나는 개인적으로 비동기 스크립트로드의 이런 방식을 선호합니다. 그리고 현장을 만들 때 Modernizr이 제공 한 기능 테스트에 의존 할 때, 어쨌든 사이트에 포함되어 있습니다. 따라서 실제로 오버 헤드가 없습니다.

여기에는 몇 가지 훌륭한 솔루션이 있지만 로컬 파일과 관련하여 한 걸음 더 나아가고 싶습니다.

Google이 실패한 시나리오에서는 로컬 소스를로드해야하지만 서버의 실제 파일이 반드시 최상의 옵션은 아닙니다. 나는 현재 동일한 솔루션을 구현하고 있기 때문에 이것을 가져옵니다. 데이터 소스에 의해 생성되는 로컬 파일로 돌아 가기를 원합니다.

그 이유는 Google에서로드 한 내용과 로컬 서버의 내용을 추적 할 때 마음의 일부를 갖기를 원하기 때문입니다. 버전을 변경하려면 로컬 사본을 Google에서로드하려는 내용과 동기화하고 싶습니다. 많은 개발자가있는 환경에서 가장 좋은 방법은이 프로세스를 자동화하여 구성 파일의 버전 번호를 변경하는 것입니다.

이론적으로 작동 해야하는 제안 된 솔루션은 다음과 같습니다.

  • 응용 프로그램 구성 파일에서는 라이브러리의 절대 URL, JavaScript API의 URL 및 버전 번호를 저장합니다.
  • 라이브러리 자체의 파일 내용을 가져 오는 클래스를 작성하고 (앱 구성에서 URL을 가져옵니다) 이름과 버전 번호로 내 데이터 소스에 저장합니다.
  • 내 로컬 파일을 DB에서 끌어 내고 버전 번호가 변경 될 때까지 파일을 캐시하는 핸들러를 작성하십시오.
  • (내 앱 구성에서) 변경되면 내 클래스가 버전 번호를 기반으로 파일 내용을 가져 와서 데이터 소스에서 새 레코드로 저장하면 핸들러가 시작하여 새 버전을 제공합니다.

이론적으로 내 코드가 올바르게 작성되면 앱 구성에서 버전 번호를 변경하면 Viola! 자동화 된 폴백 솔루션이 있으며 서버에서 실제 파일을 유지할 필요가 없습니다.

모두는 어떻게 생각합니까? 어쩌면 이것은 과잉 일지 모르지만 Ajax 라이브러리를 유지하는 우아한 방법 일 수 있습니다.

도토리

if (typeof jQuery == 'undefined') {
// or if ( ! window.jQuery)
// or if ( ! 'jQuery' in window)
// or if ( ! window.hasOwnProperty('jQuery'))    

  var script = document.createElement('script');
  script.type = 'text/javascript';
  script.src = '/libs/jquery.js';

  var scriptHook = document.getElementsByTagName('script')[0];
  scriptHook.parentNode.insertBefore(script, scriptHook);

}

CDN에서 Google 사본을 포함 시키려고 시도한 후.

HTML5에서는 설정할 필요가 없습니다 type 기인하다.

당신은 또한 사용할 수 있습니다 ...

window.jQuery || document.write('<script src="/libs/jquery.js"><\/script>');

로컬 파일을 최후의 수단으로 사용하고 싶을 수도 있습니다.

현재 JQuery의 자체 CDN은 HTTPS를 지원하지 않는 것 같습니다. 그렇다면 먼저 거기에서로드하고 싶을 수도 있습니다.

Google CDN => Microsoft CDN => 로컬 사본이 있습니다.

<!-- load jQuery from Google's CDN -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> 
<!-- fallback to Microsoft's Ajax CDN -->
<script> window.jQuery || document.write('<script src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.min.js">\x3C/script>')</script> 
<!-- fallback to local file -->
<script> window.jQuery || document.write('<script src="Assets/jquery-1.8.3.min.js">\x3C/script>')</script> 

조건부로로드 최신/레거시 jQuery 버전 및 폴백 :

<!--[if lt IE 9]>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="/public/vendor/jquery-legacy/dist/jquery.min.js">\x3C/script>')</script>
<![endif]-->
<!--[if gte IE 9]><!-->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="/public/vendor/jquery/dist/jquery.min.js">\x3C/script>')</script>
<!--<![endif]-->
  • 1 단계 : jQuery가로드되지 않았습니까? (확인하다 jQuery 변하기 쉬운)

JavaScript에서 정의되지 않은 변수를 확인하는 방법

  • 2 단계 : 동적으로 가져 오기 (백업) JavaScript 파일

다른 JavaScript 파일에 JavaScript 파일을 어떻게 포함합니까?

Google의 금지 문제로 인해 Microsoft의 CDN을 선호합니다.http://www.asp.net/ajaxlibrary/cdn.ashx

다음은 이것에 대한 훌륭한 설명입니다!

또한 지연 및 타임 아웃로드를 구현합니다!

http://happyworm.com/blog/2010/01/28/a-simple-and-robust-cdn-failover-for-jquery-14-in-one-line/

ASP.NET MVC 5를 사용하는 사람들의 경우 BundleConfig.cs 에이 코드를 추가하여 jQuery의 CDN을 활성화하십시오.

bundles.UseCdn = true;
Bundle jqueryBundle = new ScriptBundle("~/bundles/jquery", "//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js").Include("~/Scripts/jquery-{version}.js");
jqueryBundle.CdnFallbackExpression = "window.jQuery";
bundles.Add(jqueryBundle);

업데이트:
이 대답은 잘못된 것으로 판명되었습니다. 실제 설명에 대한 의견을 참조하십시오.


대부분의 질문에 대한 답변이되었지만 마지막 부분은 다음과 같습니다.

두 사본이 나오는 위험은 무엇입니까?

정말. 대역폭을 낭비하고 두 번째 쓸모없는 사본을 다운로드하여 몇 밀리 초를 추가 할 수 있지만, 둘 다 오면 실제 피해는 없습니다. 물론 위에서 언급 한 기술을 사용하여 피해야합니다.

jQuery가 아직로드되지 않은 경우 동적으로로드 해야하는 요점을 만들었고 소스가 실패하면 폴백으로 진행됩니다 (많은 답변에서 함께 스티칭). https://gist.github.com/tigerhawkvok/9673154

GIST를 계속 업데이트 할 계획이지만이 답변은 가치가있는 것에 대해 계속 업데이트 할 계획입니다!

/* See https://gist.github.com/tigerhawkvok/9673154 for the latest version */
function cascadeJQLoad(i) { // Use alternate CDNs where appropriate to load jQuery
    if (typeof(i) != "number") i = 0;
    // the actual paths to your jQuery CDNs
    var jq_paths = [
        "ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js",
        "ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.0.min.js"
    ];
    // Paths to your libraries that require jQuery
    var dependent_libraries = [
        "js/c.js"
    ];
    if (window.jQuery === undefined && i < jq_paths.length) {
        i++;
        loadJQ(jq_paths[i], i, dependent_libraries);
    }
    if (window.jQuery === undefined && i == jq_paths.length) {
        // jQuery failed to load
        // Insert your handler here
    }
}

/***
 * You shouldn't have to modify anything below here
 ***/

function loadJQ(jq_path, i, libs) { //load jQuery if it isn't already
    if (typeof(jq_path) == "undefined") return false;
    if (typeof(i) != "number") i = 1;
    var loadNextJQ = function() {
        var src = 'https:' == location.protocol ? 'https' : 'http';
        var script_url = src + '://' + jq_path;
        loadJS(script_url, function() {
            if (window.jQuery === undefined) cascadeJQLoad(i);
        });
    }
    window.onload = function() {
        if (window.jQuery === undefined) loadNextJQ();
        else {
            // Load libraries that rely on jQuery
            if (typeof(libs) == "object") {
                $.each(libs, function() {
                    loadJS(this.toString());
                });
            }
        }
    }
    if (i > 0) loadNextJQ();
}

function loadJS(src, callback) {
    var s = document.createElement('script');
    s.src = src;
    s.async = true;
    s.onreadystatechange = s.onload = function() {
        var state = s.readyState;
        try {
            if (!callback.done && (!state || /loaded|complete/.test(state))) {
                callback.done = true;
                callback();
            }
        } catch (e) {
            // do nothing, no callback function passed
        }
    };
    s.onerror = function() {
        try {
            if (!callback.done) {
                callback.done = true;
                callback();
            }
        } catch (e) {
            // do nothing, no callback function passed
        }
    }
    document.getElementsByTagName('head')[0].appendChild(s);
}

/*
 * The part that actually calls above
 */

if (window.readyState) { //older microsoft browsers
    window.onreadystatechange = function() {
        if (this.readyState == 'complete' || this.readyState == 'loaded') {
            cascadeJQLoad();
        }
    }
} else { //modern browsers
    cascadeJQLoad();
}

Google은 JQuery를 호스팅했습니다

  • IE9 이전의 IE의 주로 IE 버전 인 이전 브라우저에 관심이있는 경우 가장 널리 호환되는 jQuery 버전입니다.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  • 당신이 Oldie에 관심이 없다면, 이것은 더 작고 빠릅니다.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

백업/폴백 계획!

  • 어느 쪽이든, Google CDN이 실패하거나 (가능성이 없음),이란이나 때로는 중국과 같이 사용자가 사이트에 액세스 할 수있는 위치에서 차단 된 경우를 대비하여 로컬로의 폴백을 사용해야합니다.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script>if (!window.jQuery) { document.write('<script src="/path/to/your/jquery"><\/script>'); }
</script>

참조: http://websitespeedoptimizations.com/contentdeliverynetworkpost.aspx

나는 마지막 <to x3c를 문자열로 탈출해야한다고 생각합니다. 브라우저에서 볼 때, 이것은 이것을 스크립트 블록의 끝으로 간주합니다 (HTML Parser는 JavaScript에 대해 전혀 모르기 때문에 문자열에 나타나는 것과 실제로 스크립트를 끝내기위한 것을 구별 할 수 없습니다. 요소). 따라서 HTML 페이지 안에있는 JavaScript로 문자 그대로 나타나면 (최선의 경우) 오류가 발생하고 (최악의 경우) 큰 보안 구멍이됩니다.

<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min.js"></script>
<script>window.jQuery || document.write('<script src="js/jquery-2.0.0.min.js">\x3C/script>')</script>
if (typeof jQuery == 'undefined')) { ...

또는

if(!window.jQuery){

브라우저 가이 조건을 통과하고 jQuery가 필요한 나머지 JavaScripts를 다운로드하고 오류를 반환하기 때문에 CDN 버전이로드되지 않은 경우 작동하지 않습니다. 해결책은 해당 조건을 통해 스크립트를로드하는 것이 었습니다.

    <script src="http://WRONGPATH.code.jquery.com/jquery-1.4.2.min.js" type="text/javascript"></script><!--  WRONGPATH for test-->
  <script type="text/javascript">
  function loadCDN_or_local(){
    if(!window.jQuery){//jQuery not loaded, take a local copy of jQuery and then my scripts
      var scripts=['local_copy_jquery.js','my_javascripts.js'];
      for(var i=0;i<scripts.length;i++){
      scri=document.getElementsByTagName('head')[0].appendChild(document.createElement('script'));
      scri.type='text/javascript';
      scri.src=scripts[i];
    }
  }
  else{// jQuery loaded can load my scripts
    var s=document.getElementsByTagName('head')[0].appendChild(document.createElement('script'));
    s.type='text/javascript';
    s.src='my_javascripts.js';
  }
  }
  window.onload=function(){loadCDN_or_local();};
  </script>

ASP.NET에서 Razor Syntax를 사용 하여이 코드는 폴백 지원을 제공하고 가상 루트와 함께 작동합니다.

@{var jQueryPath = Url.Content("~/Scripts/jquery-1.7.1.min.js");}
<script type="text/javascript">
    if (typeof jQuery == 'undefined')
        document.write(unescape("%3Cscript src='@jQueryPath' type='text/javascript'%3E%3C/script%3E"));
</script>

또는 도우미를 만드십시오 (도우미 개요):

@helper CdnScript(string script, string cdnPath, string test) {
    @Html.Raw("<script src=\"http://ajax.aspnetcdn.com/" + cdnPath + "/" + script + "\" type=\"text/javascript\"></script>" +
        "<script type=\"text/javascript\">" + test + " || document.write(unescape(\"%3Cscript src='" + Url.Content("~/Scripts/" + script) + "' type='text/javascript'%3E%3C/script%3E\"));</script>")
}

다음과 같이 사용하십시오.

@CdnScript("jquery-1.7.1.min.js", "ajax/jQuery", "window.jQuery")
@CdnScript("jquery.validate.min.js", "ajax/jquery.validate/1.9", "jQuery.fn.validate")

글쓰기에도 불구하고 document.write("<script></script>") jQuery 백 오프의 경우 더 쉬운 것처럼 보이고 Chrome 은이 경우에 검증 오류를 제공합니다. 그래서 나는 "스크립트"단어를 깨는 것을 선호합니다. 그래서 위와 같이 더 안전 해집니다.

<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.1.min.js"></script>
<script>if (typeof jQuery === "undefined") {
   window.jqFallback = true;
   document.write("<scr"+"ipt src='http://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js'></scr"+"ipt>");
} </script>

장기 문제의 경우 jQuery 폴백을 기록하는 것이 좋습니다. 위의 코드에서 첫 번째 CDN을 사용할 수없는 경우 jQuery가 다른 CDN에서로드됩니다. 그러나 잘못된 CDN을 알고 영구적으로 제거 할 수 있습니다. (이 경우는 매우 예외적 인 경우) 또한 폴백 문제를 기록하는 것이 좋습니다. 따라서 Ajax로 잘못된 사례를 보낼 수 있습니다. jQuery가 정의되지 않으므로 AJAX 요청에는 바닐라 JavaScript를 사용해야합니다.

<script type="text/javascript">
    if (typeof jQuery === 'undefined' || window.jqFallback == true) {
        // XMLHttpRequest for IE7+, Firefox, Chrome, Opera, Safari
        // ActiveXObject for IE6, IE5
        var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
        var url = window.jqFallback == true ? "/yourUrl/" : "/yourUrl2/";
        xmlhttp.open("POST", url, true);
        xmlhttp.send();
    }
</script>

외부 데이터 저장소에서 자원을로드 할 수없는 것은 어렵습니다. 누락 된 기능을 찾는 것은 여기에 설명 된 바와 같이 타임 아웃을 피하기위한 수단으로 완전히 잘못된 것입니다.http://www.tech-101.com/support/topic/4499-issues-using-a-cdn/

또 다른 폴백이 대체됩니다 ajax.googleapis.com ~와 함께 cdnjs.cloudflare.com:

(function (doc, $)
{
    'use strict';

    if (typeof $ === 'undefined')
    {
        var script = doc.querySelector('script[src*="jquery.min.js"]'),
            src = script.src.replace('ajax.googleapis.com', 'cdnjs.cloudflare.com');

        script.parentNode.removeChild(script);
        doc.write('<script src="' + src + '"></script>');
    }
})(document, window.jQuery || window.Zepto);
  • 문자열에 지정하여 jQuery 버전을 고수 할 수 있습니다.
  • HTML Snips에서 작동하지 않는 자산 관리에 적합합니다.
  • The Wild에서 테스트 - 중국의 사용자에게 적합합니다.

다음과 같은 코드를 사용할 수 있습니다.

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>window.jQuery || document.write('<script type="text/javascript" src="./scripts/jquery.min.js">\x3C/script>')</script>

또한 설정하는 데 사용할 수있는 라이브러리도 있습니다. 몇몇의 스크립트에 대한 가능한 폴백 및 로딩 프로세스 최적화 :

  • 바스켓 .JS
  • 요구 사항
  • 예,

예 :

바스켓 .JS나는 지금 가장 좋은 변형이라고 생각합니다. 로컬 스토리지에서 스크립트를 캐싱하면 다음로드 속도가 빨라집니다. 가장 간단한 호출 :

basket.require({ url: '/path/to/jquery.js' });

이렇게하면 약속이 반환되며 오류에 대한 다음 호출을하거나 성공에 대한 의존성을로드 할 수 있습니다.

basket
    .require({ url: '/path/to/jquery.js' })
    .then(function () {
        // Success
    }, function (error) {
        // There was an error fetching the script
        // Try to load jquery from the next cdn
    });

요구 사항

requirejs.config({
    enforceDefine: true,
    paths: {
        jquery: [
            '//ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min',
            //If the CDN location fails, load from this location
            'js/jquery-2.0.0.min'
        ]
    }
});

//Later
require(['jquery'], function ($) {
});

예,

yepnope([{
  load: 'http://ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min.js',
  complete: function () {
    if (!window.jQuery) {
      yepnope('js/jquery-2.0.0.min.js');
    }
  }
}]);

거의 모든 공개 CDN은 매우 안정적입니다. 그러나 차단 된 Google 도메인에 대해 걱정하는 경우 다른 공개 CDN으로 간단히 감소 할 수 있습니다. pagecdn, cdnjs 또는 JSDELIVR:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
   window.jQuery || document.write('<script src="https://pagecdn.io/lib/jquery/3.2.1/jquery.min.js"><\/script>');
</script>

그러나 이러한 경우 다른 CDN을 선호하는 옵션으로 사용하고 Google CDN으로의 폴백을 사용하여 실패한 요청과 대기 시간을 피할 수 있습니다.

<script src="https://pagecdn.io/lib/jquery/3.2.1/jquery.min.js"></script>
<script>
   window.jQuery || document.write('<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"><\/script>');
</script>
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top