如果CDN失败,如何为Font Awesome提供本地后备?


14

我正在尝试开发Wordpress主题,并弄清楚如果CDN失败或者我在没有Internet连接的本地服务器上开发主题时,如何为Font Awesome提供本地后备。

我想到的解决方案是这样的(伪代码):

if ( $CDN_IS_AVAILABLE ) { 
        wp_enqueue_style( 'font-awesome', '//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css', false );
    } else {
        wp_enqueue_style('font-awesome', get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css', false, '4.0.3' );
    }

谢谢!



感谢@MayeenulIslam,但即使CDN可用,它似乎也会返回false。
纳氏2014年

2
至少有两种方法,但是使用CDN的唯一原因是性能,但是我敢肯定,您会发现任何方法都会使性能变差,所以恕我直言毫无意义。如果主题是共享/出售,我只会去本地复制,请确保用户愿意,可以让他们轻松地切换到CDN版本。如果主题仅适合您自己,请选择一个或另一个。考虑到大多数著名的CDN的停机时间都非常短(根据cdnperf.com,bootstrapcdn是最可靠的停机之一)。
gmazzap

您有通用的想法如何应对初学者的后备吗?我知道JS后备依赖检查变量,我不确定检查CSS负载依赖什么。
2014年

1
您当然可以做到,我绝不会为此要求PHP的额外请求。这就是这里的挑战-对于初学者,我根本想不出检查CSS负载的好方法。
Rarst

Answers:


15

问题是,我非常确定无法检查是否通过PHP将CSS有效地添加到了页面:CSS是由浏览器解析的,因此是客户端,对服务器端完全没有影响。

当然,在PHP中可以检查CDN是否响应。

选项1

发送一个请求,如果它以HTTP状态200响应,请使用它。就像是:

function font_awesome_css() {
    $url = 'http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css';
    $cdn = wp_remote_get( $url );
    if ( (int) wp_remote_retrieve_response_code( $cdn) !== 200 ) {
        $url = get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css';
    }
    wp_enqueue_style( 'font-awesome', $url, false );
}

导致2个HTTP请求,一个用于检查,第二个用于嵌入式CSS:真的很差

选项2

function font_awesome_css() {
    $url = 'http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css';
    $cdn = wp_remote_get( $url );
    if ( (int) wp_remote_retrieve_response_code( $cdn ) === 200 ) {
        $css = wp_remote_retrieve_body( $cdn );
        add_action( 'wp_head', function() use( $css ) {
            $absolute = "//netdna.bootstrapcdn.com/font-awesome/4.0.3/fonts/";
            $css = str_replace( "../fonts/", $absolute, $css );
            echo '<style type="text/css">' . $css . '</style>';
        } );
    } else {
        $url = get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css';
        wp_enqueue_style( 'font-awesome', $url, false );
    }
}

这甚至更糟

  • 它破坏了wp_enqueue_style工作流程:如果插件添加了Font Awesome,它将被添加2次。
  • HTTP请求的数量是相同的,但是通常2个请求并行运行,因此以这种方式,页面的PHP生成速度变慢,因为它需要等待第一个请求响应。
  • 这也可以防止浏览器缓存CSS,因此,如果在不同页面中使用相同样式,则会在访问的每个页面上强制执行CDN请求。使用常规工作流程时,第一个CSS之后的页面将从缓存中获取。

所以,真的,不要在家中这样做。

真正重要的是,使用PHP可以检查CDN请求,但不能验证CSS,因此所有努力最终都会导致性能变差,而不是更好。

真诚的,如果您的主题是公共主题,建议您仅使用本地副本,为用户提供选择CDN的方法:

if ( ! function_exists( 'font_awesome_css' ) ) {
    function font_awesome_css() {
        $_url = get_template_directory_uri() . '/css/font-awesome/css/font-awesome.min.css';
        $url = apply_filters( 'font_awesome_css_url', $_url );
        wp_enqueue_style( 'font-awesome', $url, false );
    }
}

因此,用户可以使用子主题完全覆盖该功能,还可以使用'font_awesome css_url'过滤器更改URL。

还应考虑到一些高端托管服务提供商会自动将本地资产转换为CDN资产,并且有一些插件可以让CDN拥有一切。这就是公共主题完全不应使用CDN的原因。

如果主题适合您自己,则进行选择。考虑到大多数著名的CDN的停机时间都非常短(根据cdnperf.com,bootstrapcdn是最可靠的停机之一)。我很确定您的主机的停机时间比bootstrapcdn大,因此与带有破损图标的网站相比,人们更有可能根本看不到您的网站。

肮脏的方式

如前所述,PHP无法检查CSS,因为CSS渲染发生在客户端,但是您可以使用客户端检查:JavaScript。

首先使用CDN嵌入CSS:

function font_awesome_css() {
    $url =  '//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css';
    wp_enqueue_style( 'font-awesome', $url, false );
} 

之后,在页脚中添加一些JavaScript:

/*
Normally the JS should be properly enqueued and the URL
passed via wp_enqueue_script, but this is a proof of concept,
more than real code.
*/
add_action( 'wp_footer', function() {
    $cssurl = get_template_directory_uri() . '/css/';
    ?>
    <span id="facheck" data-cssuri="<?php echo $cssurl; ?>" class="fa" style="display:none">
    </span>
    <script>
        jQuery(document).ready(function($) {
            var $check = $('#facheck');
            if ( $check.css('fontFamily') !== 'FontAwesome' ) {
                // Font Awesome not loaded!
                // Remove current CSS link
                $('#font-awesome-css').remove;
                // Add the local version
                var local = '<link rel="stylesheet" type="text/css" href="' +
                    $check.data('cssuri') + // This is the theme CSS folder URL
                    'font-awesome/css/font-awesome.min.css" />';
                $('head').append( local );
            }
        });
    </script>
    <?php
});

此代码在页面加载时运行,并检查添加到类为“ fa”的页脚的不可见范围是否将font-family属性设置为“ FontAwesome”。这是由Font Awesome设置的,因此,如果不正确,则表示未加载CSS。如果发生这种情况,代码将使用JavaScript将本地CSS附加到head。

(要测试此代码,您可以通过wp_enqueue_style错误的CDN URL 进行嵌入,然后查看会发生什么情况)

因此,在极少数情况下无法使用CDN的情况下,所有样式都会按预期显示(在几毫秒内,用户会看到“残破的” CSS图标,因为在页面加载后添加了CSS)。

现在,考虑到CDN非常可靠,对于不到1%会看到图标破损的人来说,值得这样做吗?回答这个问题留给您。


很长时间以来,我还没有看到像这样的话题如此复杂而深入的方法。那使我彻底清醒了。现在,我想我将CDN用作主题选项,让用户可以自由选择。谢谢!
纳氏2014年

我一直在寻找这样的解决方案,因此对于最后一句话,“对于不到1%会看到图标破损的人来说,这样做值得这样做吗?” 也许添加一个加载微调器可以解决?
卡尔·阿尔贝托

2

服务器端检查也不是防弹的。如果您的服务器位于加利福尼亚州,则您的支票将使用加利福尼亚州CDN的数据中心。如果您的用户位于中国,则他们可能会使用完全不同的数据中心。至少,我就是这样认为的。

无论如何,这是一个改进的jquery解决方案:

http://jsfiddle.net/skibulk/fp1gqnyc/

<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="/wordpress//css/font-awesome.min.css" rel="stylesheet">');
        }
        $span.remove();
    })(jQuery);
</script>

出色的方法,而且是一种有效的方法,除了字体超赞外,还感谢您的分享。我应该补充一点,与其他解决方案(例如本文中以及本文其他地方)不同,这也是不可知的。
oucil 2015年

1
由于没有超时,如果CDN实例在检查后完成加载,则最终将加载Font Awesome两次fontFamily
Dan Dascalescu 2015年

1
@DanDascalescu默认情况下不是同步加载(阻止)CSS文件吗?我相信在CDN加载失败之前页面不会继续吗?
2015年

1
CSS确实可以同步加载,但是字体本身仅在使用它的文本呈现时才加载。这是一个显示JSbin
Dan Dascalescu 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.