最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

css - Adding external stylesheet after ALL other styles

programmeradmin1浏览0评论

The theme I'm using makes extensive use of internal stylesheets to style various types of pages and their elements. For example, through their plugin UI, I can configure a specific page's hero layout and content... including font, size and color for various text elements. After configuring the hero and publishing the page, an internal stylesheet is added to the page's <head> tag:

<style id="ut-hero-custom-css" type="text/css">
    #ut-hero .hero-inner {
        text-align: right
    }
    .hero-description {
        color: #000000;
    }
    .hero-description {
        background: #FCB54B;
        padding-bottom: 0;
        margin-bottom: 5px;
    }
    #ut-hero .hero-title {
        color: #1777FF;
    }
</style>

Unfortunately, the plugin is limited in what it allows me to customize so I need to add some of my own CSS to fine tune things. Let's say I want to display a border around the block of text with class="hero-description". I'd need to add

.hero-description {
    border: 1px solid #c00;
} 

and have it be applied to the page AFTER the initial declaration above. Adding it my child-theme's style.css file or any other CSS file I register and enqueue adds it BEFORE. I was hoping that I could specify the inline stylesheet embedded by the plugin as a dependency for my new CSS file when enqueueing it, but I don't see any handle or reference to it in $wp_styles so I couldn't do that. Can you even register an internal stylesheet?

Anyway, this can be broken down to a very general problem. I want to have the "last word" on the page's CSS (excluding inline styles and scoped elements). Is there not a direct way to specify that a line of code such as:

<link rel="stylesheet" src="mycss.css">

always be included right before the closing </head> tag?

The theme I'm using makes extensive use of internal stylesheets to style various types of pages and their elements. For example, through their plugin UI, I can configure a specific page's hero layout and content... including font, size and color for various text elements. After configuring the hero and publishing the page, an internal stylesheet is added to the page's <head> tag:

<style id="ut-hero-custom-css" type="text/css">
    #ut-hero .hero-inner {
        text-align: right
    }
    .hero-description {
        color: #000000;
    }
    .hero-description {
        background: #FCB54B;
        padding-bottom: 0;
        margin-bottom: 5px;
    }
    #ut-hero .hero-title {
        color: #1777FF;
    }
</style>

Unfortunately, the plugin is limited in what it allows me to customize so I need to add some of my own CSS to fine tune things. Let's say I want to display a border around the block of text with class="hero-description". I'd need to add

.hero-description {
    border: 1px solid #c00;
} 

and have it be applied to the page AFTER the initial declaration above. Adding it my child-theme's style.css file or any other CSS file I register and enqueue adds it BEFORE. I was hoping that I could specify the inline stylesheet embedded by the plugin as a dependency for my new CSS file when enqueueing it, but I don't see any handle or reference to it in $wp_styles so I couldn't do that. Can you even register an internal stylesheet?

Anyway, this can be broken down to a very general problem. I want to have the "last word" on the page's CSS (excluding inline styles and scoped elements). Is there not a direct way to specify that a line of code such as:

<link rel="stylesheet" src="mycss.css">

always be included right before the closing </head> tag?

Share Improve this question asked Jun 25, 2017 at 17:19 Daveh0Daveh0 1912 silver badges13 bronze badges 1
  • You could just make the rule more specific, then it'd take precedence over the other rule, no matter which order it was loaded, even if it appeared first. You shouldn't need to rely on the ordering of CSS loading to style things right for things as specific as hero images – Tom J Nowell Commented Dec 20, 2017 at 15:07
Add a comment  | 

4 Answers 4

Reset to default 1

It's not elegant but it works.

Add these lines to functions.php:

ob_start();

add_action('shutdown', function() {
    $final = '';
    $levels = ob_get_level();
    for ($i = 0; $i < $levels; $i++) {
        $final .= ob_get_clean();
    }

    // append styles just before </head>
    $final = str_replace( "</head>", '<link rel="stylesheet" src="mycss.css"></head>', $final );

    echo $final;
}, 0);

Alternatively you can move all the inline styles at the beginning of the head, better if just after the title tag:

ob_start();

add_action('shutdown', function() {
    $final = '';
    $levels = ob_get_level();
    for ($i = 0; $i < $levels; $i++) {
        $final .= ob_get_clean();
    }

    /* Adjust the final output */

    // load HTML DOM
    $dom= new DOMDocument(); 
    $dom->preserveWhiteSpace = false;
    $dom->formatOutput       = true;
    $dom->loadHTML( '<?xml encoding="utf-8" ?>' . $final );

    // collect styles and remove them from DOM
    $inline_styles = "";
    $styles = $dom->getElementsByTagName("style");
    foreach( $styles as $style )
    {
        $inline_styles .= $dom->saveHTML( $style );
        $style->parentNode->removeChild( $style );
    }

    $final = $dom->saveHTML();

    // strip utf-8 workaround
    $final = str_replace( '<?xml encoding="utf-8" ?>', "", $final );

    // append styles after <title>
    $final = str_replace( "</title>", "</title>\n" . $inline_styles, $final );

    echo $final;
}, 0);

You would add dependencies to your wp_enqueue_style() function calls.

function my_enqueues() {
    wp_enqueue_style( 'style-one', '{path}' );
    wp_enqueue_style( 'style-two', '{path}', array( 'style-one' ) );
    wp_enqueue_style( 'style-three', '{path}', array( 'style-two' ) );
    wp_enqueue_style( 'style-final', '{path}', array( 'style-three' ) );
}
add_action( 'wp_enqueue_scripts', 'my_enqueues' );

What this code does is make each style sheet dependent on the previous one. So they will load in the order style-one, style-two, etc.

Of course one of the {path} placeholders should be your style.css file called with get_stylesheet_uri();.

If you want to load one after a plugin has loaded one that overrides, then try using the plugins_loaded hook:

function my_plugin_overrides() {
   wp_deregister_style( 'plugin-styles' ); // OPTIONAL
   wp_enqueue_style( 'plugin-css-overrides', '{path}', array( 'deps' ) );
}
add_action( 'plugins_loaded', 'my_plugin_overrides' );

Since WP 4.7 the WP dashboard includes a CSS customizer (Appearence->Cusomize->Additional CSS). This might be a solution for your theme specific CSS as WP adds the style block to <head> after enqueued CSS and possibly other additions by theme.

Normal practice as per Cedons enqueing answer or jimihenrik's comment should work.

However; it appears this theme needs a "non-standard" solution (I like your JS solution) - alternatives include an edited copy of header.php in child theme.

"an internal stylesheet is added to the page's <head>"

The theme could be adding in a variety of ways in header.php e.g. hard coding; via a theme "action hook"; via wp-head

The last part of header.php typically contains:

<?php possibly_themes_own_action_hook(); ?>
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
  Some HTML for header and navigation & other stuff prior to Loop adding say H1 title

If theme does not have header.php or it is missing </head> then relevant code is probably in templates.

In your child header.php just above </head> (if not present see below) you could either:

  • hard code your CSS or stylesheet link above </head>
  • or <php include('path/to/mycss.css');?>

  • or add your own action:

     my_add_to_head(); 
    

    and in your functions.php

     function my_head_function() {
     ?>
     <style>.hero-description {border:1px solid #c00;}</style> 
     <?php
     // or stylesheet link or file_get_contents to get css file and echo
     // + any other stuff you want to add to head
     }
     add_action('my_add_to_head', 'my_head_function');
    

Solutions are bad practice especially if someone else ends up having to maintain but may be the best option with your theme.

"when i used wp_head, it ended up in the tag with all the JavaScript files."

If you mean within the body tag then there is a coding error in the theme. Otherwise it is "non-standard" design and could cause many plugins to "fail". Either wp_head(); is after the body tag or "wp_head" is used to insert <body> and maybe </head>.

If </head> is not in header.php or templates then adding the above "solutions" just above wp_head(); might still work but plugin issues will remain.

I am completely blocked here. SO, for the time being I will be using the following "workaround" so that I can at least continue development:

$(function() {
    $('head').append('
      <link rel="stylesheet" type="text/css" src="mycss.css">
    ');
});

Definitely not the "right" way, but I should be able to easily port my new, overriding styles (as referenced in mycss.css above) to wherever they belong when done the "right" way when I get it figured out.

发布评论

评论列表(0)

  1. 暂无评论