Perfect CSS styles loading

I try to load CSS style in what seems to me the most optimized way possible with Jekyll

With a Liquid trick, I ask Jekyll to include only css blocs that are used in the page and to display them directly in the HEAD tag.

Problem

I want to be able to display the site as quickly as possible to the visitor without having to load useless files. Without having to ask the browser to parse CSS information that is useless for the current page (therefore no global file which contains all the styles of the site). I try to give the visitor only what they need when they need it to view the current page.

Keep in mind that parsing and applying CSS styles requires resources and memory from the browser. The more we send it, the longer it takes for slow and / or old devices.

For more accessibility, I want my HTML document to be W3C validated. CSS styles must therefore be placed in a STYLE tag, in the HEAD tag

Everything must be minified and uncommented to gain a few extra kb.

The solution must be scalable. I need to be able to have as many templates, layouts and stylesheets as I want.

I am using Jekyll, I must be able to do this easily using Liquid tags.

In short, a HTML file which contains the HTML content as well as the necessary styles placed in the HEAD tag. So that the CSS content is gzipped by the web server along with the rest of the HTML file. We end up with very little data to transfer.

My solution

File structure

To make it more convenient to me, I create a common.html file which contains the setup of my html pages (from <html> to </html>) into which the layout content will be inserted. And in the same way, I created a common.css file which will contain the CSS used for all pages of the website.

If I have an html file that I may include in my content at different places (in a layout, or directly in a post), then I create a CSS file of the same name. Example: video.html, video.css

For each of my templates, I created a CSS file of the same name (if there is a need to associate an independent CSS to it). Example: post.css, posts.css

It looks like this:

 _includes/
      common.html
      common.css
      post.css
      posts.css
      video.html
      video.css
 _layouts/
      default.html
      post.html
      posts.css

Layouts

In my layout, the first thing I do is capturing the CSS styles of the current layout in a generated_css variable:

<!-- _layouts/post.html (1/3) -->
{% capture generated_css %}
    {{ generated_css }}
    {% include posts.css %}
{% endcapture %}

(I concatenate a possible existing generated_css variable to allow to add all the styles used in the page. Here it won’t be useful, but I use the same formula everywhere)

Then I capture all of my content in a generated_content variable:

<!-- _layouts/post.html (2/3) -->
{% capture generated_content %}
    <section class="post">
    [...]
    </section>
{% endcapture %}

… after which, I include my common.html file

<!-- _layouts/post.html (3/3) -->
{% include common.html %}

My common.html file will then receive the two variables generated_css and generated_content. He will just have to place them in the right place on the page:

<!-- _include_/common.html -->
<html>
    <head>
        <style>
            {{ generated_css }}
        </style>
    </head>
    <body>
        {{ generated_content }}
    </body>
</html>

Posts and pages

In terms of posts and pages, it’s a little different. If I create a variable generated_css directly in the content, it will not be passed to the layout. So I have to put the information in the configuration. For example, for this page, I’m loading CSS styling which allows me to display code blocks with syntax highlighting. So I add the YML variable contains_code like this:

    ‑‑‑
    # 2021-09-07-my-blog-post.md
    layout: post
    contains_code: true

    ‑‑‑

    Hello world :
    ```
    <b>Hello world</b> is bold
    ```

… and in my common.html file, I can then indicate that if contains_code is true, then I load the CSS style for the syntax highlighting of the code (the file _includes/code.css for example).

<!-- _include_/common.html -->

{% if page.contains_code == true %}
    {% capture generated_css %}
        {{ generated_css }}
        {% include code.css %}
    {% endcapture %}
{% endif %}

<html>
[...]
</html>

Even more expandable …

The solution above works fine. On the other hand, it is quite difficult to extend. I have to add a condition in common.html for every possible stylesheet.

To have a more extensible result, I can add an html tag directly in the MarkDown content of my post which looks like this:

<!--INCLUDE_CSS code.css END_INCLUDE_CSS-->

And then, in my common.html file, I can ask it to find all of these tags that are in the content of my page (in the generated_content variable), to extract the name of the file to include, list them, remove duplicates and add their content to the generated_css variable:

<!-- _include_/common.html -->


{% assign CSS_list = "" %}

{% assign CSS_blocs = generated_content | split: "<!--INCLUDE_CSS" %}

{% for CSS_bloc in CSS_blocs %}
  {% assign CSS_bloc_name_array = CSS_bloc | split: "END_INCLUDE_CSS-->" %}
  {% assign CSS_bloc_name_size = CSS_bloc_name | size %}
  {% assign CSS_bloc_name = CSS_bloc_name_array[0] | strip %}
  {% if CSS_bloc_name_size > 1%}
    {% assign CSS_list = CSS_list | append: "," | append: CSS_bloc_name %}
  {% endif %}
{% endfor %}

{% assign CSS_list = CSS_list | split: "," | uniq  %}

{% for CSS_inc in CSS_list  %}
    {% if CSS_inc !="" %}
        {% capture generated_css %}
            {{ generated_css }}
            {% include {{ CSS_inc }} %}
        {% endcapture %}
    {% endif %}
{% endfor %}

<html>
[...]
</html>

This time, it kinda looks nice. We just have to minify it. With Jekyll, I use the jekyll-minifier plugin with the option compress_css: true and remove_comments: true. This way I end up with a well-filled, well-minified <style> tag. And my personal tags <!-- INCLUDE_CSS code.css END_INCLUDE_CSS --> disappear from the code in production.

Collateral benefit

I can add Liquid tags in my stylesheets. For example, I define a color in my _config.yml file and use it in my CSS code:

a{
    color:{{ site.color }};
}

Other methods

I think it is possible to do this with SASS, but I don’t know how to use it very well.

Well I’m pretty happy with the result !

Hope it helps !

Did you know ? I have absolutly no mean to know if your read this blog post or not. I respect your privacy too much to install any kind of analytic tracker or some cookie sh*t. So.. if you want to let me know you read it and (dis)like it, you'll have to leave a comment below !

Your comment

About yourself

You're not a naughty spammer bot, are you ?

Go to top