วิธีโหลดไฟล์ CSS โดยใช้ Javascript


316

เป็นไปได้ไหมที่จะนำเข้า CSS สไตล์ชีทไปยังหน้า html โดยใช้ Javascript ถ้าเป็นเช่นนั้นจะทำอย่างไร?

PS จาวาสคริปต์จะถูกโฮสต์ในเว็บไซต์ของฉัน แต่ฉันต้องการให้ผู้ใช้สามารถใส่<head>แท็กของเว็บไซต์ของพวกเขาและมันควรจะสามารถนำเข้าไฟล์ css ที่โฮสต์บนเซิร์ฟเวอร์ของฉันลงในหน้าเว็บปัจจุบัน (ทั้งไฟล์ css และไฟล์จาวาสคริปต์จะโฮสต์บนเซิร์ฟเวอร์ของฉัน)


นอกจากนี้ยังมีคำถามเกี่ยวกับ jQuery stackoverflow.com/questions/2685614/ …
jcubic

คำตอบ:


416

นี่คือวิธี "โรงเรียนเก่า" ในการดำเนินการซึ่งหวังว่าจะใช้ได้กับทุกเบราว์เซอร์ ในทางทฤษฎีคุณจะใช้setAttributeน่าเสียดายที่ IE6 ไม่รองรับอย่างสม่ำเสมอ

var cssId = 'myCss';  // you could encode the css path itself to generate id..
if (!document.getElementById(cssId))
{
    var head  = document.getElementsByTagName('head')[0];
    var link  = document.createElement('link');
    link.id   = cssId;
    link.rel  = 'stylesheet';
    link.type = 'text/css';
    link.href = 'http://website.com/css/stylesheet.css';
    link.media = 'all';
    head.appendChild(link);
}

ตัวอย่างนี้ตรวจสอบว่า CSS ถูกเพิ่มไปแล้วหรือไม่ดังนั้นมันจะเพิ่มเพียงครั้งเดียว

ใส่รหัสนั้นลงในไฟล์ javascript ให้ผู้ใช้ปลายทางใส่เพียงแค่จาวาสคริปต์และตรวจสอบให้แน่ใจว่าเส้นทาง CSS นั้นสมบูรณ์ดังนั้นจึงโหลดจากเซิร์ฟเวอร์ของคุณ

VanillaJS

นี่คือตัวอย่างที่ใช้ JavaScript ธรรมดาเพื่อแทรกลิงก์ CSS ลงในheadองค์ประกอบตามส่วนของชื่อไฟล์ของ URL:

<script type="text/javascript">
var file = location.pathname.split( "/" ).pop();

var link = document.createElement( "link" );
link.href = file.substr( 0, file.lastIndexOf( "." ) ) + ".css";
link.type = "text/css";
link.rel = "stylesheet";
link.media = "screen,print";

document.getElementsByTagName( "head" )[0].appendChild( link );
</script>

ใส่รหัสก่อนheadแท็กปิดและ CSS จะโหลดก่อนที่จะแสดงผลหน้า การใช้.jsไฟล์JavaScript ( ) ภายนอกจะทำให้แฟลชของเนื้อหาที่ไม่มีการจัดรูปแบบ ( FOUC ) ปรากฏขึ้น


6
สิ่งที่เกี่ยวกับการเรียกกลับเมื่อไฟล์ CSS โหลด?
jchook

1
นี่ค่อนข้างซับซ้อนกว่าที่จะทำอย่างน่าเชื่อถือ ตอนนี้ไลบรารี Javascript ที่เป็นที่นิยมมักจะมีรูปแบบการโหลดจาวาสคริปต์และสไตล์ชีทพร้อมด้วยการติดต่อกลับ เป็นตัวอย่างที่เห็นยูอิรับ

9
อาจจะเป็นการดีกว่าถ้าใช้อักขระที่แตกต่างจาก $ สำหรับทางลัดเอกสารเนื่องจากอาจรบกวน jQuery ได้อย่างง่ายดาย (เช่นในกรณีของฉัน);)
Zathrus Writer

2
@jonnybojangles การใช้ jQuery.noConflict จะหมายถึงการเปลี่ยนชื่อการอ้างอิงทั้งหมดของคุณเป็น jQuery เป็น $ มันจะง่ายกว่าที่จะใช้ชื่อตัวแปรอื่นสำหรับตัวโหลด CSS
tommypyatt

2
@jchook ฉันสามารถแนบการติดต่อกลับโดยเพิ่มlink.onload = function(){ ... }ก่อนผนวก
Lounge9

74

หากคุณใช้ jquery:

$('head').append('<link rel="stylesheet" type="text/css" href="style.css">');

1
มันจะทำงานได้ก็ต่อเมื่อมีการอัดสไตล์ชีทก่อน pageload ใช่ไหม เมื่อฉันเรียกใช้คำสั่งนี้ภายในคอนโซลในหน้าโหลดด้วยไฟล์ css ที่ฉันได้เป็นเจ้าภาพใน Dropbox มันจะไม่ทำงาน ความคิดใด ๆ ว่าฉันสามารถทำงานนี้ได้อย่างไร:$('head').append('<link rel="stylesheet" type="text/css" href="https://dl.dropboxusercontent.com/s/ep1nzckmvgjq7jr/remove_transitions_from_page.css">');
thomas

50

ฉันเดาว่าสคริปต์นี้น่าจะทำ:

<script type="text/javascript" src="/js/styles.js"></script>

ไฟล์ JS นี้มีคำสั่งต่อไปนี้:

if (!document.getElementById) document.write('<link rel="stylesheet" type="text/css" href="https://stackoverflow.com/css/versions4.css">');

ที่อยู่ของจาวาสคริปต์และ CSS จะต้องสมบูรณ์หากพวกเขาจะอ้างถึงเว็บไซต์ของคุณ

CSS เทคนิคการนำเข้าจำนวนมากได้รับการกล่าวถึงในนี้"บอกว่าไม่มีการแฮ็ก CSS ด้วยเทคนิคที่แตกแขนง"บทความ

แต่บทความ"การใช้ JavaScript เพื่อเพิ่มสไตล์ชีต CSS ของพอร์ตเล็ตแบบไดนามิก"ยังกล่าวถึงความเป็นไปได้ของ CreateStyleSheet (วิธีการที่เป็นกรรมสิทธิ์สำหรับ IE):

<script type="text/javascript">
//<![CDATA[
if(document.createStyleSheet) {
  document.createStyleSheet('http://server/stylesheet.css');
}
else {
  var styles = "@import url(' http://server/stylesheet.css ');";
  var newSS=document.createElement('link');
  newSS.rel='stylesheet';
  newSS.href='data:text/css,'+escape(styles);
  document.getElementsByTagName("head")[0].appendChild(newSS);
}
//]]>

นี่คือสิ่งที่ฉันมาพร้อมกับการเพิ่มdocument.createStyleSheet()เบราว์เซอร์ที่ไม่ได้: stackoverflow.com/questions/524696/…
Christoph

1
ไม่แน่ใจในกรณีนี้ แต่ในบางกรณีdocument.writeไม่แนะนำให้ทำเพราะมันจะเขียนทับเนื้อหาทั้งหมดในเว็บไซต์ของคุณ
Eduard Luca

@VonC มีฟังก์ชั่นรับ<style>องค์ประกอบโดยตรงแทนที่จะสมมติว่าเป็นลูกคนแรกของ<head>ผ่าน("head")[0]หรือไม่
Pacerier

@Pacerier ผมเชื่อว่าคุณจะพบว่ามีการหารือในgroups.google.com/forum/#!topic/prototype-scriptaculous/... ตัวอย่างเช่น:var style = document.getElementsByTagName("style")[0];
VonC

20

Element.insertAdighborHTMLมีการสนับสนุนเบราว์เซอร์ที่ดีมากและสามารถเพิ่มแผ่นสไตล์ในหนึ่งบรรทัด

document.getElementsByTagName("head")[0].insertAdjacentHTML(
    "beforeend",
    "<link rel=\"stylesheet\" href=\"path/to/style.css\" />");

12

หากคุณต้องการทราบ (หรือรอ) จนกว่าสไตล์จะโหลดงานนี้:

// this will work in IE 10, 11 and Safari/Chrome/Firefox/Edge
// add ES6 poly-fill for the Promise, if needed (or rewrite to use a callback)

let fetchStyle = function(url) {
  return new Promise((resolve, reject) => {
    let link = document.createElement('link');
    link.type = 'text/css';
    link.rel = 'stylesheet';
    link.onload = function() { resolve(); console.log('style has loaded'); };
    link.href = url;

    let headScript = document.querySelector('script');
    headScript.parentNode.insertBefore(link, headScript);
  });
};

ฉันจะใช้สิ่งนี้ได้อย่างไร
Raj Sharma

คุณจะทำ fetchStyle (url). แล้ว (ฟังก์ชั่น () {สิ่งที่ไปที่นี่}) อ่านคำสัญญา
Ben Taliadoros

8

ฉันรู้ว่านี่เป็นด้ายเก่า แต่สวยมา 5 เซ็นต์ของฉัน

มีวิธีอื่นในการทำเช่นนี้ขึ้นอยู่กับความต้องการของคุณ

ฉันมีกรณีที่ฉันต้องการไฟล์ css ที่จะใช้งานเพียงครู่เดียว เช่นเดียวกับการเปลี่ยน CSS เปิดใช้งาน css และหลังจากเหตุการณ์อื่นอีกครั้ง

แทนที่จะโหลด css แบบไดนามิกแล้วลบออกคุณสามารถเพิ่ม Class / an id ต่อหน้าองค์ประกอบทั้งหมดใน css ใหม่จากนั้นเพียงแค่เปลี่ยน class / id ของโหนดฐานของ css ของคุณ (เช่นแท็ก body)

คุณจะใช้วิธีนี้ในการโหลดไฟล์ css ได้มากขึ้นในตอนแรก แต่คุณมีวิธีการเปลี่ยนเลย์เอาท์ css ที่มีพลวัตมากขึ้น


7

ในเบราว์เซอร์ที่ทันสมัยคุณสามารถใช้promiseเช่นนี้ สร้างฟังก์ชั่นโหลดเดอร์ที่มีคำสัญญาใน:

function LoadCSS( cssURL ) {

    // 'cssURL' is the stylesheet's URL, i.e. /css/styles.css

    return new Promise( function( resolve, reject ) {

        var link = document.createElement( 'link' );

        link.rel  = 'stylesheet';

        link.href = cssURL;

        document.head.appendChild( link );

        link.onload = function() { 

            resolve(); 

            console.log( 'CSS has loaded!' ); 
        };
    } );
}

เห็นได้ชัดว่าคุณต้องการสิ่งที่ทำหลังจากโหลด CSS คุณสามารถเรียกใช้ฟังก์ชันที่จำเป็นต้องเรียกใช้หลังจากโหลด CSS ดังนี้:

LoadCSS( 'css/styles.css' ).then( function() {

    console.log( 'Another function is triggered after CSS had been loaded.' );

    return DoAfterCSSHasLoaded();
} );

ลิงค์ที่มีประโยชน์หากคุณต้องการเข้าใจในเชิงลึกว่ามันทำงานอย่างไร:

เอกสารทางการเกี่ยวกับสัญญา

คู่มือที่มีประโยชน์สำหรับสัญญา

วิดีโอแนะนำที่ยอดเยี่ยมเกี่ยวกับสัญญา


6

ใช้รหัสนี้:

var element = document.createElement("link");
element.setAttribute("rel", "stylesheet");
element.setAttribute("type", "text/css");
element.setAttribute("href", "external.css");
document.getElementsByTagName("head")[0].appendChild(element);

4

มีปลั๊กอิน jquery ทั่วไปที่โหลดไฟล์ css และ JS ซิงค์และ asych ตามต้องการ นอกจากนี้ยังติดตามว่ามีการโหลดอะไรแล้ว :) ดู: http://code.google.com/p/rloader/


4

นี่คือวิธีที่มีวิธีการสร้างองค์ประกอบของ jQuery (การตั้งค่าของฉัน) และการโทรกลับonLoad:

var css = $("<link>", {
  "rel" : "stylesheet",
  "type" :  "text/css",
  "href" : "style.css"
})[0];

css.onload = function(){
  console.log("CSS IN IFRAME LOADED");
};

document
  .getElementsByTagName("head")[0]
  .appendChild(css);



2

ด้านล่างรหัสเต็มใช้สำหรับโหลด JS และ / หรือ CSS

function loadScript(directory, files){
  var head = document.getElementsByTagName("head")[0]
  var done = false
  var extension = '.js'
  for (var file of files){ 
    var path = directory + file + extension 
    var script = document.createElement("script")
    script.src = path        
    script.type = "text/javascript"
    script.onload = script.onreadystatechange = function() {
        if ( !done && (!this.readyState ||
            this.readyState == "loaded" || this.readyState == "complete") ) {
            done = true
            script.onload = script.onreadystatechange = null   // cleans up a little memory:
            head.removeChild(script)  // to avoid douple loading
        }
  };
  head.appendChild(script) 
  done = false
 }
}

function loadStyle(directory, files){
  var head = document.getElementsByTagName("head")[0]
  var extension = '.css'
  for (var file of files){ 
   var path = directory + file + extension 
   var link = document.createElement("link")
   link.href = path        
   link.type = "text/css"
   link.rel = "stylesheet" 
   head.appendChild(link) 
 }
}

(() => loadScript('libraries/', ['listen','functions', 'speak', 'commands', 'wsBrowser', 'main'])) ();
(() => loadScript('scripts/', ['index'])) ();

(() => loadStyle('styles/', ['index'])) ();

1

ฉันต้องการแบ่งปันอีกวิธีหนึ่งในการโหลดไม่เพียง แต่ css แต่สินทรัพย์ทั้งหมด (js, css, images) และจัดการกับเหตุการณ์onloadสำหรับไฟล์จำนวนมาก async-assets-loaderมัน ดูตัวอย่างด้านล่าง:

<script src="https://unpkg.com/async-assets-loader"></script>
<script>
var jsfile = "https://code.jquery.com/jquery-3.4.1.min.js";
var cssfile = "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css";
var imgfile = "https://logos.keycdn.com/keycdn-logo-black.png";
var assetsLoader = new asyncAssetsLoader();
assetsLoader.load([
      {uri: jsfile, type: "script"},
      {uri: cssfile, type: "style"},
      {uri: imgfile, type: "img"}
    ], function () {
      console.log("Assets are loaded");
      console.log("Img width: " + assetsLoader.getLoadedTags()[imgfile].width);
    });
</script> 

ตามที่async สินทรัพย์โหลดเอกสาร


0
var fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("th:href", "@{/filepath}")
fileref.setAttribute("href", "/filepath")

ฉันใช้ไธเมลีเอฟและมันใช้ได้ดี ขอบคุณ


การเพิ่มth:hrefแอตทริบิวต์ในฝั่งไคลเอ็นต์คืออะไร มันจะไม่ถูกประมวลผลโดย Thymeleaf ดังนั้นจึงดูเหมือนซ้ำซ้อนที่นี่
Slava Semushin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.