django-critical icon indicating copy to clipboard operation
django-critical copied to clipboard

Inlines critical path CSS and defers loading full CSS asynchronously.

=============== django-critical

.. image:: https://badge.fury.io/py/django-critical.png :target: https://badge.fury.io/py/django-critical

.. image:: https://travis-ci.org/martinblech/django-critical.png?branch=master :target: https://travis-ci.org/martinblech/django-critical

.. image:: https://coveralls.io/repos/martinblech/django-critical/badge.png?branch=master :target: https://coveralls.io/r/martinblech/django-critical?branch=master

Inlines critical path CSS and defers loading full CSS asynchronously.

Documentation

The full documentation is at https://django-critical.readthedocs.org.

Quickstart

  • Install django-critical:

    .. code-block:: bash

      pip install django-critical
    
  • Add critical to your INSTALLED_APPS setting:

    .. code-block:: python

      INSTALLED_APPS = (
          # other apps
          "critical",
      )
    
  • Add critical.middleware.CriticalCssMiddleware to your MIDDLEWARE_CLASSES setting:

    .. code-block:: python

      MIDDLEWARE_CLASSES = (
          # other middlewares
          "critical.middleware.CriticalCssMiddleware",
      )
    
  • Point your CRITICAL_PENTHOUSE_PATH setting to the correct path, e.g.:

    .. code-block:: python

      CRITICAL_PENTHOUSE_PATH = os.path.join(
          BASE_DIR, 'node_modules/penthouse/penthouse.js')
    
  • If phantomjs is not in your PATH, you have to set CRITICAL_PHANTOMJS_PATH and point it to your phantomjs binary:

    .. code-block:: python

      CRITICAL_PHANTOMJS_PATH = os.path.join(
          BASE_DIR, 'node_modules/phantomjs/bin/phantomjs')
    

How it works

django-critical is activated by adding {% load critical %} to your template.

django-critical then parses the HTML between {% critical %} and {% endcritical %} and searches for CSS.

.. code-block:: html

    {% critical %}
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
    <style>
      .jumbotron h1 {
        color: red;
      }
    </style>
    {% endcritical %}

It downloads and concatenates all that CSS and uses penthouse_ to extract the critical path CSS rules from it, which end up inlined and minified in place of the original CSS.

.. code-block:: html

    <style>html{font-family:sans-serif;-webkit-text-size-adjust:100%…</style>

Later in the HTML, before the closing </body> tag, the {% critical_async %} template tag takes care of loading the rest of the CSS using FilamentGroup's loadCSS_.

Caching

django-critical calculates the critical path CSS for the first request, caches the result and reuses this CSS verbatim for further requests. Most web applications have different critical path CSS for different groups of pages, though. This can be solved using the {% critical_key "<key>" %} template tag, so that different templates can have different caching keys.

Is this stable and ready for production use?

No. django-critical is in a very early stage of development, so you should use it at your own risk. Bug reports_ and contributions_ are welcome, though!

.. _penthouse: https://github.com/pocketjoso/penthouse/ .. _loadCSS: https://github.com/filamentgroup/loadCSS .. _Bug reports: https://github.com/martinblech/django-critical/issues .. _contributions: https://github.com/martinblech/django-critical/pulls