DEV Community

Cover image for Developing with css inline
Roberto Manchado
Roberto Manchado

Posted on • Edited on

Developing with css inline

First all, dont try this technic free. I use this technic when not use WebPack :

composer require symfony/webpack-encore-bundle
Enter fullscreen mode Exit fullscreen mode

I hate use dependences for my projects when, you can like backend developer, write inline inside style tag, and then, remove them from the code and compress on fly.

let's see how...

This is:


class CssCompressService {

    public function compress(string $html): Response
    {
        $buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '',     $this->getCssInline($html));

        $buffer = str_replace(': ', ':', $buffer);

        $buffer = str_replace(array("\r\n", "\r", "\n", "\t", '  ', '    ', '    '), '', $buffer);

        ob_start("ob_gzhandler");

        $response = new Response($buffer);
        $response->headers->set('Content-type',' text/css');

        return $response;
    }

    private function getCssInline($html) : string
    {
        preg_match_all('/<style[^>]*>([^<]+)<\/style>/', $html, $matches, PREG_OFFSET_CAPTURE);

        $css = '' ;
        foreach ($matches[0] as $match) {
            $css .= strip_tags($match[0]) ;
        }

        return $css;
    }
}
Enter fullscreen mode Exit fullscreen mode

then you have to add this tag inside your head:


    <link href="{{ path(app.request.get('_route'),app.request.get('_route_params')) }}?compress=true" rel="stylesheet">
Enter fullscreen mode Exit fullscreen mode

the twig function app.request.get allow get the name of your Controller that intercept your request and the params of your request. This way, you dont need write the path of your Controller each time.

Inside your Controller, you only need add this snippet of code:


if($this->requestStack->getCurrentRequest()->query->has('compress')){
    return $this->cssCompressService->compress($html);
}
Enter fullscreen mode Exit fullscreen mode

Now, we need remove the style tag from the html code rendered. We can use the DomDocument class for get the style nodes and remove them.


class DomService {

    public function __construct(private readonly TidyService $tidyService){}

    public function output(string $html): Response
    {
        $dom = new DOMDocument('1.0', 'UTF-8');
        @$dom->loadHTML($html);
        $script_tags = $dom->getElementsByTagName('style');

        while($script_tags->item(0) != null) {
            if(is_object($script_tags->item(0)->parentNode)) {
                $script_tags->item(0)->parentNode->removeChild($script_tags->item(0));
            }
        }
        return $this->tidyService->parse(new Response($dom->saveHTML()));

    }

}
Enter fullscreen mode Exit fullscreen mode

Pay attention on the constructor class. We are injected the TidyService. A class that use the Tidy extension php, for sort the html rendered. Very beautifull....

And our Controller is as follow:


 #[Route('/blog/{page}', name: 'app_blog')]
    public function blog(
        PostRepository $postRepository,
        int $page = 1
    ): Response
    {
        $this->seoMetaTagsService->generate(
            $this->requestStack->getCurrentRequest(),
            true,
            [],
            'Blog',
            ''
        );

        $html = $this->render('blog/index.html.twig', [
            'posts_results_paginated' => $postRepository->paginate($page),
            'posts_results_all' => $postRepository->findAll()
        ])->getContent() ;
        if($this->requestStack->getCurrentRequest()->query->has('compress')){
            return $this->cssCompressService->compress($html);
        }

        return $this->domService->output($html);

    }
Enter fullscreen mode Exit fullscreen mode

With this way, you can write css inline as follow:


{% macro print(skill,loop) %}
    {% if loop.first %}
    <style>
        td a {
            color: #1c262f;
        }
        td a:hover {
            color: #46a80f;
            text-decoration: none;
        }
        td i {
            cursor: pointer;
        }
    </style>
    {% endif %}
    <tr>
        <td><strong>{{ skill.name }}</strong></td>
        <td>{{ skill.description }}</td>
        <td style="width: 100px">
            <a href="{{ path('skill_update', {'skillId': skill.id }) }}" title="update skill">
                <i class="fa fa-edit"></i>
            </a>
            <a href="{{ path('skill_delete', {'skillId': skill.id }) }}" title="remove skill">
                <i class="fa fa-eraser"></i>
            </a>
        </td>
    </tr>
{% endmacro %}
Enter fullscreen mode Exit fullscreen mode

In our macros from Twig, you can write css inline, without fear that the style tag embbebed on your html code. Your css code will be compress and when you do a request to the controller, you will have a response with the css compressed like that :


body {background-color:#1c262f;}.navbar.top-nav-collapse {border-bottom:1px dashed darkseagreen;}.active > .page-link, .page-link.active {background-color:#1c262f;border-color:#1c262f;}.page-link {color:#1c262f;}.page-link:hover {color:seagreen;}.dataTables_wrapper .dataTables_length select {border:1px solid black;}.dataTables_wrapper .dataTables_filter input {border:1px solid black;}button {padding:0 15px 0 15px;}button i {padding:5px ;}table#datatable {background-color:#c1d6cc;}body {background-color:darkseagreen;}section#posts {margin-top:5em;}td a {color:#1c262f;}td a:hover {color:#46a80f;text-decoration:none;}td i {cursor:pointer;}td img {border:1px solid darkslategrey;}
Enter fullscreen mode Exit fullscreen mode

Some considerations

  • When you put css inside your macros, you should add the loop variable if you are using a loop, because the style css inline will be repeated.
  • You will have two requests. One, the request with the compress parameter that render your css inline compress without tools like WebPack, UglyFy, CSS compresors, etc etc, and the normal request that render your template Twig.
  • You can use the style tags as many times as you want. They will be removed from your code and injected on the fly in the header.
  • If you know about css, you can use the specificity for avoid css style colisions more easy. Each page, macro, template,,, have own css.

Top comments (0)