问题描述

我阅读了 WP 文档,which pointed to this gist,正确的方式来排列 IE 的样式是通过使用 $wp_styles 。我猜测这对于脚本也是如此。

以这些例子为例

选项一 – 使用 wp_scripts

add_action('wp_print_scripts', function() {
    global $wp_scripts;
    wp_enqueue_script( 'html5shiv', 'https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js', array( 'bootstrap' )  );
    $wp_scripts->add_data( 'html5shiv', 'conditional', 'lt IE 9' );
} );

选项二 – 使用 wp_scriptsis_IE

add_action('wp_print_scripts', function() {
    global $wp_scripts, $is_IE;
    if($is_IE) {
        wp_enqueue_script( 'html5shiv', 'https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js', array( 'bootstrap' )  );
        $wp_scripts->add_data( 'html5shiv', 'conditional', 'lt IE 9' );
    }
} );

选择三 – 只是回头说:

add_action('wp_head', function(){
    echo '<!--[if lt IE 9]><script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script><![endif]-->' . "n";
});

选项四 – 将其排列在头上:

add_action('wp_print_scripts', function(){
        wp_enqueue_script( 'html5shiv', 'https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js', array( 'bootstrap' )  );
});

第二个选择。看起来很酷,因为它在 non-IE 浏览器上看起来有点干净。但是我不知道它是否具有任何速度优势,或者单独的检查会减慢。除此之外,我似乎无法弄清楚选项一比选项 3 或 4 更好的原因。


这个问题的原因

我正在使用 Genesis 框架和 they include HTML5shiv,就像下面的例子似乎对我来说似乎不对:

add_action( 'wp_head', 'genesis_html5_ie_fix' );
/**
 * Load the html5 shiv for IE8 and below. Can't enqueue with IE conditionals.
 */
function genesis_html5_ie_fix() {
    if ( ! genesis_html5() )
        return;
    echo '<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->' . "n";
}

最佳解决方案

而选项 5 是在客户端检测它是什么浏览器,并为您的脚本直接创建一个脚本元素到 dom,像 google 分析一个 FB SDK 。

这样做的优点是只在需要完成的地方进行浏览器检测,浏览器和仅在需要时加载 IE 特定的脚本。

在精神上,它非常类似于你的第三个选择,只是更通用。

Sidenote:is_IE 像所有其他服务器端浏览器检测一样应该避免,因为它们会中断缓存。

次佳解决方案

一般来说,脚本和样式不应直接打印到页面。

原因是另一个插件或主题可能再次添加相同的脚本,并且您获得相同的脚本添加了两次或更多次。

如果您以正确的方式排队资产,如果其他代码再次排入同一个资产,则会添加一次。

因此,您应该跳过选项 3 和 4 。

关于方案 2,作为 Mark Kaplun pointed out,它利用 server-side 浏览器检测,这是永远不会很实惠的,即使这样,不要让你选择浏览器的版本,在你的情况下,它将包括脚本甚至在现代的 IE 版本中,不需要它。

所以,实际上,选项 1 是你提出的最好的选择。

我会做的唯一的改变:

  • 使用'wp_enqueue_scripts'动作,而不是'wp_print_scripts'

  • 使用 wp_scripts()函数 istead 访问全局

就像是:

add_action('wp_enqueue_scripts', function() {
    wp_enqueue_script(
       'html5shiv',
       'https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js',
       array( 'bootstrap' ),
       '3.7.2',
       false
    );
    wp_scripts()->add_data( 'html5shiv', 'conditional', 'lt IE 9' );
} );

如果另外一个插件再次插入'html5shiv'脚本,那么它将被添加一次。

请注意,使用上面的代码段,页面上的打印是:

<!--[if lt IE 9]>
<script type='text/javascript' src='https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js'></script>
<![endif]-->

此条件由浏览器 (客户端) 解析,而不是服务器端,因此它是经济实惠的,您只需要为要定位的 IE 版本添加脚本。

如果您需要更多地了解客户端平台 (OS,屏幕类型和分辨率,浏览器的具体详细版本…),则唯一的方法是使用一些 javascript 来嗅探这些细节,并将脚本动态添加到 DOM(按照 Mark Kaplun 解决方案),但是如果知道”browser family” 和主要版本对你来说足够了,我的建议是使用这个解决方案。

第三种解决方案

要扩展使用 wp_scripts()时,不要使用全局变量的 @gmazzap 建议,wp_scripts()有一个快捷方式来添加名为 wp_script_add_data 的条件注释,同样用于条件样式的 wp_style_add_data

所以使用 Wordpress 4.2 的条件的正确方法就是这样:

/**
 * IE enqueue HTML5shiv with conditionals
 * @link http://tiny.cc/html5shiv
 */
function wpse_213701_enqueue_html5shiv()  {
    wp_enqueue_script( 'html5shiv',
        'https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js',
        array(),
        false,
        false
    );
    wp_script_add_data( 'html5shiv', 'conditional', 'lt IE 9' );
}
add_action('wp_enqueue_scripts', 'wpse_213701_enqueue_html5shiv');

然而,上面的例子是使用 HTML5shiv,这是一个独特的情况。因为它必须被加载到头部,所以你可以像下面的例子那样做一些例子,如果你担心像 Roots Soil 这样的插件从头中删除所有的脚本。


很可能你不会遇到这样的情况。这是一个非常不稳定的事情,因为需要很多脚本来加载头部。脚本中的脚本应该通过在排列脚本时将 $in_footer 变量设置为 true 来完成。所以如果你使用根或任何缓存插件的事情,不要计划在一切正常工作,如何你想要的开箱即用。

这是一个丑陋的例子,你可以做什么:

add_action( 'wp_head', 'wpse_213701_check_html5shiv', 1 );
function wpse_213701_check_html5shiv() {
    remove_action( 'wp_head', 'genesis_html5_ie_fix' );
    if ( !has_filter( 'wp_head', 'wp_enqueue_scripts' ) && !wp_script_is( 'html5shiv', 'done' ) ) {
        add_action('wp_head', 'wpse_213701_echo_html5shiv');
        wp_dequeue_script('html5shiv');
    }
}
function wpse_213701_echo_html5shiv() {
    echo '<!--[if lt IE 9]><script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script><![endif]-->' . "n";
}

这是过分的,但它仍然不能保证它会奏效。在过去的 4 年中,html5shiv 已经占据了许多名称,这使得它被注册/排队了几个不同的句柄 (html5,html5shiv,html5shim,themename-html5shiv,html5-ie-fix 和 html5-polyfill 等等) 。此外,它通常是 bundled with modernizr 。考虑到这一点,如果你认为上面的例子是荒谬的,那么你也可以将脚本添加到你的孩子主题中的 wp_head 中,因为插件 html5shiv 句柄最有可能命名为别的东西。

更新 (使用此方法将脚本移动到页脚):

这引发了对 Roots/Soil Github 页面的一些操作。这可能是最好的方法 (由 @grappler 建议),仍然将脚本移动到页脚。几年前,@ kaiser 的 blog 发布了类似的方法。

function grappler_move_js_to_footer() 
    $scripts = wp_scripts();
    foreach( $scripts->registered as $script ) {
        if ( 'html5' == $script->handle ) {
            wp_script_add_data( $script->handle, 'group', 0 );
        } else {
            wp_script_add_data( $script->handle, 'group', 1 );
        }
    }
}
add_action( 'wp_enqueue_scripts', 'grappler_move_js_to_footer', 99 );

至于 Mark Kaplan 的建议和什么 toscho mentioned here,你不应该使用选项 2 的 $ is_IE 方法。显然,如果 HTTP 标头 Vary:User-Agent 没有被发送,你将向高速缓存中的用户发送错误的输出,导致这些用户中断。关于浏览器端检测 here is a long thread of examples 可以做些什么。即使是 client-side 检测也有其陷阱。


在一天结束的时候,也许最好的答案是不要使用任何这些方法,并忘记了自 Microsoft has dropped support for them as of January 12 以来的遗留浏览器。

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。