1

I am trying to improve the performance of magento complying with the requirements of google page speed and I have come across this, I don't know if it is a bug, if I am missing something or what it is exactly. The thing is, I have to add the critical inline css and defer the loading of the rest of the css to the bottom of the page. I get to load the critical css inline using the native magento option. enter image description here

The problem now comes when I use this option Magento by default copies the css that you have added in default_head_block.xml at the bottom of the page, but does not "delete" them from the header. Moreover, the css files in the header add a preload tag,

enter image description here

I would like to know how they solved this, since I suppose it is a common problem in the rest of the websites.

Thank you very much for the help.

2 Answers 2

0

My understanding is you need to take the CSS that you add to critical.css out of the 'normal' CSS/LESS files, as stated in the docs:

Do not duplicate styles in critical.css and non-critical style sheets.

If you keep the styles in both you will end up with duplicated CSS.

7
  • Hi, I know, but the problem is not that I have to eliminate the duplicate css, but how do I eliminate the minified and merged css files from the header, if using the critical css configuration it already puts them at the bottom of the page? May 20, 2021 at 9:00
  • Do you have CSS merging enabled? I wonder if that conflicts with the critical CSS functionality
    – Ben Crook
    May 20, 2021 at 9:18
  • The only other idea I have is that both of those files are somehow critical, surely preload should only be added to the critical css files
    – Ben Crook
    May 20, 2021 at 9:20
  • If I have it activated, I do not know if that conflicts, I will try to deactivate it and see if it works as it should. May 20, 2021 at 9:27
  • I have tried to disable the merge, but it does not solve the problem of removing / moving the files from the head, it adds "preload" to all the css. Any more ideas? May 20, 2021 at 10:35
0

It seems like a Magento bug. You can override AsyncCssPlugin.php for this. Check the below code and try to implement this code:

Create File: app/code/Fix/CriticalCss/registration.php

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Fix_CriticalCss',
    __DIR__
);

Create File: app/code/Fix/CriticalCss/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
    <module name="Fix_CriticalCss" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Theme"/>
        </sequence>
    </module>
</config>

Create File: app/code/Fix/CriticalCss/etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Theme\Controller\Result\AsyncCssPlugin" type="Fix\CriticalCss\Controller\Result\AsyncCssPlugin" />
</config>

Create File: app/code/Fix/CriticalCss/Controller/Result/AsyncCssPlugin.php

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Fix\CriticalCss\Controller\Result;

use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;
use Magento\Framework\App\Response\Http;

/**
 * Plugin for asynchronous CSS loading.
 */
class AsyncCssPlugin
{
    private const XML_PATH_USE_CSS_CRITICAL_PATH = 'dev/css/use_css_critical_path';

    /**
     * @var ScopeConfigInterface
     */
    private $scopeConfig;

    /**
     * @param ScopeConfigInterface $scopeConfig
     */
    public function __construct(ScopeConfigInterface $scopeConfig)
    {
        $this->scopeConfig = $scopeConfig;
    }

    /**
     * Load CSS asynchronously if it is enabled in configuration.
     *
     * @param Http $subject
     * @return void
     */
    public function beforeSendResponse(Http $subject): void
    {
        $content = $subject->getContent();

        if (\is_string($content) && strpos($content, '</body') !== false && $this->scopeConfig->isSetFlag(
            self::XML_PATH_USE_CSS_CRITICAL_PATH,
            ScopeInterface::SCOPE_STORE
        )) {
            $cssMatches = [];
            // add link rel preload to style sheets
            $content = preg_replace_callback(
                '@<link\b.*?rel=("|\')stylesheet\1.*?/>@',
                function ($matches) use (&$cssMatches) {
                    $cssMatches[] = $matches[0];
                    preg_match('@href=("|\')(.*?)\1@', $matches[0], $hrefAttribute);
                    $href = $hrefAttribute[2];
                    if (preg_match('@media=("|\')(.*?)\1@', $matches[0], $mediaAttribute)) {
                        $media = $mediaAttribute[2];
                    }
                    $media = $media ?? 'all';
                    $loadCssAsync = sprintf(
                        '<link rel="preload" as="style" media="%s" .
                         onload="this.onload=null;this.rel=\'stylesheet\'"' .
                        'href="%s">',
                        $media,
                        $href
                    );

                    //return $loadCssAsync;
                    return;
                },
                $content
            );

            if (!empty($cssMatches)) {
                $content = str_replace('</body', implode("\n", $cssMatches) . "\n</body", $content);
                $subject->setContent($content);
            }
        }
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.