【问题标题】:Programmatic inclusion of CSS pages from JavaScript breaks styiling image url从 JavaScript 中以编程方式包含 CSS 页面会破坏图像 url 的样式
【发布时间】:2014-02-25 23:47:28
【问题描述】:

目录结构:

html/index.html  
html/css/css.css  
html/css/img/avatar.png

css.css 的内容:

body {
  background-image: url("./img/avatar.png");    
}

如果在 index.html 中使用“链接”标签包含 css.css 文件,它可以正常工作,并且 avatar.png 显示为页面背景:

<link rel="STYLESHEET" type="text/css" href="./css/css.css">

但是,如果使用 JavaScript 代码包含 css.css 文件,那么控制台会显示错误:

function load_css(){
  var xhr = new XMLHttpRequest();
  xhr.onload = function () {
  if (xhr.readyState === 4)
    if (xhr.status === 200) {
      var oNew = document.createElement('style');
      oNew.rel = 'STYLESHEET';
      oNew.type = 'text/css';
      oNew.textContent = xhr.responseText;
      document.getElementsByTagName("head")[0].appendChild(oNew);
    }
  }
  xhr.open("GET", './css/css.css', false);
  xhr.send(null);
}

load_css();

控制台:

GET http://localhost/html/img/avatar.png 404 (Not Found) 

它不适用于所有浏览器。

看起来,当使用上述方法以编程方式包含 CSS 文件时,该 CSS 内的相对链接相对于包含它们的 HTML 文件而不是包含它们的 CSS 文件变得相对。

有什么补救建议吗?

【问题讨论】:

  • 使用 CSS 文档的绝对路径。
  • 另外,我不知道您的设置中的 /html/ 是什么,但看起来您的文件夹少了一个。我的 XAMPP 设置是 http://localhost/*site-folder*/yadayada

标签: javascript html css xmlhttprequest stylesheet


【解决方案1】:

为什么要使用 同步 XMLHttpRequest 将 CSS 注入 &lt;style&gt; 元素?您可以创建一个新的&lt;link&gt; 并将其附加到&lt;head&gt;,这应该可以解决您的问题。它也可以跨域工作,并且在过去十年中得到所有浏览器的支持。

function load_css(url) {
  var link = document.createElement('link');
  link.type = 'text/css';
  link.rel = 'stylesheet';
  link.href = url;
  document.getElementsByTagName('head')[0].appendChild(link);
}

然后像这样加载你的 CSS:

load_css('/css/css.css');

【讨论】:

  • 抱歉回复晚了。我需要同步加载,因为代码必须在脚本执行继续之前加载。我加载了两种类型的文件:一种 var oNew = document.createElement("script");和另一个 var oNew = document.createElement('style');我喜欢你的解决方案,如果它可以让它同步工作。
  • 我将尝试对“var link.onload=function(){processNextLink()}”使用带有“onload”事件的队列。希望它会起作用,将发布更新。
【解决方案2】:

导致问题:

如果你使用&lt;link&gt;,文件路径是用2层完成的:

  • 1 级:您的“html”所在的位置。
  • 2 级:“css”文件所在的位置。

如果你通过“javascript”输入“css”,路径将只有1级,换句话说,使用javascript css将等于与“html”相同的文件夹。


随着对静态文件和动态工作的 HTTP 请求播放

Javascript 是“静态的东西”变成了“动态的”,但是当在“HTML 请求”中插入一个元素时,甚至可以理解为来自静态文件的调用(在这种情况下,就好像你已经用完了 &lt;style&gt; )。


可能的解决方案

1 - 使用绝对路径

所以解决方案是对 CSS 调用的图像使用“绝对路径”,例如:

background-image: url(http://website.com/css/img/avatar.png);

background-image: url(http://website.com/html/css/img/avatar.png);

2 - 使用 String.replace

另一种可能的解决方案是在 Javascript 中使用String.replace,请参阅:

function RelativeToAbsolute(a){
    var b = String(window.location).replace(/\/[^\/]+$/, "").replace(/\/$/, "")+"\/css/";
    if(a){
        a = String(a);
        a = a.replace(/url\(((http|https|file[:]\/\/)[:]\/\/)/gi, "url(!$1");//block next replace in absolute paths (if absolute paths to your css)
        a = a.replace(/url\([.]\//gi, "url({PATH}");//define replace for paths like "./css/img/"
        a = a.replace(/url\(([a-z])/gi, "url({PATH}$1");//define replace for paths like "css/img/"
        a = a.replace(/url\(\{PATH\}([^)]+[)])/gi, "url("+b+"$1");//set absolute path
        a = a.replace(/url\([!]((http|https|file[:]\/\/)[:]\/\/)/gi, "url($1");//replace "!" in absolute paths (if absolute paths to your css)
        myLOG(a);
        return a;
    } else {
        myLOG("CSS invalid");
    }
    return a;
}
...
//With your CSS
oNew.textContent = RelativeToAbsolute(xhr.responseText);

3 - CACHE:使用 .htaccess(或等效的)缓存静态文件

当用ajax访问时,css文件会被添加到缓存中。

当使用&lt;link href=""&gt;访问css文件时,它已经在缓存中了。

您的 .htaccess:

<FilesMatch "\.(css)$">
#1 year
ExpiresDefault A29030400
Header set Cache-Control "max-age=29030400, public"
</FilesMatch>

你的javascript:

function load_css(){
  var xhr = new XMLHttpRequest();
  var url = './css/css.css';
  xhr.onload = function () {
  if (xhr.readyState === 4)
    if (xhr.status === 200 || xhr.status === 304) {//304 not modified
      var oNew = document.createElement('link');
      oNew.rel = 'stylesheet';
      oNew.type = 'text/css';
      oNew.href = url;
      document.getElementsByTagName("head")[0].appendChild(oNew);
    }
  }
  xhr.open("GET", url, true);//use async
  xhr.send(null);
}

load_css();

提示:

对您的服务器有好处的东西会使用带有 CDN 的图像(例如,带有“image.”前缀的子域),例如:

background-image: url(http://images.website.com/css/img/avatar.png);

background-image: url(http://images.website.com/html/css/img/avatar.png);

【讨论】:

  • 我正在使用一堆 CSS 文件,它们是 JS 框架的一部分。它是许多具有现有代码的文件。我正在寻找 JavaScript 脚本级别的解决方案。
  • @Gonki 就像我说的当你使用“javascript”插入“css”时,就好像你用完了&lt;style&gt;。所以此时最好的解决方案可能是修改你的css。
  • 我修改了 CSS 希望它是一个临时的补救措施。如果我将包含修改后的 css 的 html 文件放入另一个目录,则这些更新将无效。在这种情况下,我非常希望避免更改 CSS 文件,因为它们是流行的 JS 框架的一部分。
  • @Gonki 如果图像使用绝对路径,不明白这怎么会失败?不是必须具有绝对路径的css是图像。我编辑了我的答案。
  • 如果使用绝对路径,则分发存在问题。就我而言,现在相对路径是 localhost。我希望我的代码在下载后可以与现有的 JS 框架一起使用,而无需修改框架的大量 CSS 代码。
【解决方案3】:

我的最终解决方案涉及在标题中使用@idbehold 的 appendChild() 建议。有一个循环构建必须包含的所有文件的数组堆栈。然后将 onLoad 事件添加到每个“链接”元素,检查它何时是堆栈中的最后一个元素,然后将名为 isLoading 的全局变量设置为 false。然后检查主函数调用: if (isLoading){setTimeout(function(){ js2dx.init(data) }, 1);return;}

它将等到所有文件加载完毕后再继续。一个非常丑陋的解决方案。 :(

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-22
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    • 2017-03-24
    • 2011-06-16
    相关资源
    最近更新 更多