Safari ignore CSS :not() rule

Viewed 225

I got the problem with Safari 13.0.5 (14608.5.12)

About safari information

Trying to modify some of the WordPress Divi builder plugin styles, I came across an unexpected problem with the inability to apply a negative rule that would prevent the plugin from styling if necessary in a particular place.

Modifying file:

src/wordpress/wp-content/plugins/divi-builder/includes/builder/styles/frontend-builder-plugin-style.min.css

So I came from this:

#et-boc .et-l .hentry,
#et-boc .et-l a,
#et-boc .et-l a:active,
#et-boc .et-l blockquote,
#et-boc .et-l div:not(.woocommerce-message,.star-rating),
#et-boc .et-l em,
#et-boc .et-l form,
#et-boc .et-l h1,
#et-boc .et-l h2,
#et-boc .et-l h3,
#et-boc .et-l h4,
#et-boc .et-l h5,
#et-boc .et-l h6,
#et-boc .et-l hr,
#et-boc .et-l iframe,
#et-boc .et-l img,
#et-boc .et-l input,
#et-boc .et-l label,
#et-boc .et-l li,
#et-boc .et-l object,
#et-boc .et-l ol,
#et-boc .et-l p,
#et-boc .et-l span,
#et-boc .et-l strong,
#et-boc .et-l textarea,
#et-boc .et-l ul,
#et-boc .et-l video {background: 0 0;
    border: none;
    -moz-border-radius: 0;
    -webkit-border-radius: 0;
    border-radius: 0;
    -webkit-box-shadow: none;
    -moz-box-shadow: none;
    box-shadow: none;
    color: inherit;
    letter-spacing: normal;
    margin: 0;
    outline: 0;
    padding: 0;
    text-align: inherit;
    text-shadow: inherit;
    -moz-transition: none;
    -o-transition: none;
    -webkit-transition: none;
    transition: none;
    vertical-align: baseline;
}

To this:

#et-boc .et-l *:not(.no-divi-styles) .hentry,
#et-boc .et-l *:not(.no-divi-styles) a,
#et-boc .et-l *:not(.no-divi-styles) a:active,
#et-boc .et-l *:not(.no-divi-styles) blockquote,
#et-boc .et-l *:not(.no-divi-styles) div:not(.woocommerce-message,.star-rating),
#et-boc .et-l *:not(.no-divi-styles) em,
#et-boc .et-l *:not(.no-divi-styles) form,
#et-boc .et-l *:not(.no-divi-styles) h1,
#et-boc .et-l *:not(.no-divi-styles) h2,
#et-boc .et-l *:not(.no-divi-styles) h3,
#et-boc .et-l *:not(.no-divi-styles) h4,
#et-boc .et-l *:not(.no-divi-styles) h5,
#et-boc .et-l *:not(.no-divi-styles) h6,
#et-boc .et-l *:not(.no-divi-styles) hr,
#et-boc .et-l *:not(.no-divi-styles) iframe,
#et-boc .et-l *:not(.no-divi-styles) img,
#et-boc .et-l *:not(.no-divi-styles) input,
#et-boc .et-l *:not(.no-divi-styles) label,
#et-boc .et-l *:not(.no-divi-styles) li,
#et-boc .et-l *:not(.no-divi-styles) object,
#et-boc .et-l *:not(.no-divi-styles) ol,
#et-boc .et-l *:not(.no-divi-styles) p,
#et-boc .et-l *:not(.no-divi-styles) span,
#et-boc .et-l *:not(.no-divi-styles) strong,
#et-boc .et-l *:not(.no-divi-styles) textarea,
#et-boc .et-l *:not(.no-divi-styles) ul,
#et-boc .et-l *:not(.no-divi-styles) video {background: 0 0;
    border: none;
    -moz-border-radius: 0;
    -webkit-border-radius: 0;
    border-radius: 0;
    -webkit-box-shadow: none;
    -moz-box-shadow: none;
    box-shadow: none;
    color: inherit;
    letter-spacing: normal;
    margin: 0;
    outline: 0;
    padding: 0;
    text-align: inherit;
    text-shadow: inherit;
    -moz-transition: none;
    -o-transition: none;
    -webkit-transition: none;
    transition: none;
    vertical-align: baseline;
}

This solution works fine at Chrome, Firefox, etc! ...except Safari =/

enter image description here

What's the problemm with this browser?

2 Answers

You cannot use a list of selectors in :not() for all browsers yet, which is why you don't see this work in Safari — the whole selector list gets dropped. See MDN's reference.

You need to split this into two :not()s:

...
#et-boc .et-l *:not(.no-divi-styles) div:not(.woocommerce-message):not(.star-rating),
...

In any case, it is better to avoid such complex code in styles and not stumble on browser bugs. I did not manage to find out why Safari behaves in this way, however, with regard to the DIVI plug-in, such a solution would complicate the code even more. I am sure that in future versions the bug will be fixed.

However I found another simple solution: since DIVI plugin is quite aggressive to any code placed in it, then a simple way out was to put the applications and the necessary parts of the code that fall into the stream into an iframe that completely isolates the code you need from third-party interference.

For example you can do so:

interest.pug

extends index
block content
    .interest
        .container.container--content.interest__container
            script.
                function interestIframeOnLoad () {
                    var interestIframe = document.getElementById('interest__iframe')
                    interestIframe.contentWindow.postMessage({
                        selector: '#interest',
                        //...your_app_init_options_here
                    }, '*')
                }

            iframe(
                src='./interest__iframe.pug'
                class='interest__iframe'
                id='interest__iframe'
                frameborder='0'
                onload='javascript: interestIframeOnLoad()'
            )

interest__iframe.pug

doctype html
html(lang='en')
    head
        meta(charset='UTF-8')
        meta(name='viewport', content='width=device-width, initial-scale=1.0')
        title Interest inner app
        script(src='../../assets/js/interest.js')

    body
        #interest
        script.
            let appWasLaunched = false;
            const iframe = window.top.document.getElementById('interest__iframe');

            function launchApp(options) {
                window.app.interest(options);
            }

            window.addEventListener('message', e => {
                if (!appWasLaunched) {
                    appWasLaunched = true;
                    var data = e.data;
                    launchApp(data);
                }
            }, false);

interest.js

import Vue from 'vue'
import App from './App.vue'

export default function interest (options) {
    new Vue({
        data: options,
        render: (h) => h(App)
    }).$mount(options.selector);
}

window.app = window.app || {};
window.app.interest = interest;

The code above uses the parsel bundler Therefore, you can use the .pag extension in the iframe src attribute and you can even use .scss and ES6 inside that iframe which basically closed the problem with the DIVI plugin in my case. I hope my answer will be useful to someone

Related