2

I am writing an app for any CMS where I don't know the surrounding CSS or its selectors, but want my app to always look the same.

I'm having the issue, that if a external selector selects one of my elements for example via button{height: 100px;} and my selector button .class{width:100px;} does not specify the height attribute, the external selector puts this attribute onto my buttons and changes its style.

This is just a plain example and you might say, "just specify height in your selector, too", i cant put every thinkable attribute into my selectors and overwrite everything that could have somewhere been set.

See this fiddle for an easy example: https://jsfiddle.net/u4rvx6Lk/, where i don't want the first selector to set the border on my blue element, but of course, it does.

I have tried all: unset; and all: initial; but it just wont work and certainly wont in Internet Explorer.

I also know about scoped CSS but this also doesn't work very reliably.

(Further Info: It is an angular 1.x app that will mainly be injected into WordPress CMS pages, I compile my CSS using sass)

6
  • Maybe you are looking for important! Commented Jan 9, 2017 at 20:27
  • 1
    if i dont set the attribute i cant set !important Commented Jan 9, 2017 at 20:28
  • Like this: jsfiddle.net/u4rvx6Lk/1 Commented Jan 9, 2017 at 20:31
  • 2
    It is essentially impossible to stop styles from styling your elements if they have access to them. In a few years you might be able to achieve it with the Shadow DOM, but it isn't really possible now. If CSS has access to your elements, it can style them. That's just how it works... Commented Jan 9, 2017 at 20:34
  • @lonesomeday but can i overwrite any given attributes with something? similar to all: unset; Commented Jan 9, 2017 at 20:35

4 Answers 4

2

The solution that worked for me is using the CSS property all set to a value of revert.

.css-class {
    all: revert;
}

The mozilla docs for revert explains it nicely:

The revert CSS keyword rolls back the cascade so that the property takes on the value it would have had if there were no styles in the current style origin.

For firefox and chrome, use unset:

.css-class {
    all: unset;
}

See browser hacks for using "media query hacks" for checking the current browser for a cross-browser solution. Also, see this fiddle where the blue box does not inherit the height property:

I hope this solution will work in your project as well.

Sign up to request clarification or add additional context in comments.

5 Comments

it inherits both the height and the border in my chrome and firefox. in your example fiddle
im sorry, but this changes nothing about the blue boxes style neigther in firefox nor in chrome
This is happening because all: unset unsets all the element's inherited properties to their default. height, for example, is initially set to auto and does not depend on the height of the parent.
but if i add height:auto; instead of all: unset; it works, so i guess you're wrong about that
@Jim your fiddle doesnt work because auf the //- Comments, if you update your post i will tag your answer as correct
1

It is virtually impossible to stop CSS code from modifying your elements, as the web currently exists. What you are essentially talking about is sandboxing your elements, preventing them from being modified by other code.

You can do this with an iframe, but that's horrid and almost certainly too much faff.

On the other hand, the future is bright! There is a feature coming called the Shadow DOM, which essentially works to allow you to implement your own elements and sandbox them from the rest of your code. It's already how elements like input and video work behind the scenes: now we get to do what the browsers have been doing for years.

You can create an element: we'll call it solid-button.

<solid-button></solid-button>

We'll then write the code to go inside it. We'll put this in a template so it doesn't appear on the screen till we want it:

<template id="solid-button-src">
  <style>
    button {
      width: 100px;
      height: 100px;
      background-color: green;
      border: solid 1px black;
    }

  </style>
  <button></button>
</template>

We then use a little bit of Javascript to create the Shadow DOM and add the content in the template into it:

customElements.define('solid-button', class extends HTMLElement {
  constructor() {
    super();

    const shadowRoot = this.attachShadow({
      mode: 'open'
    });
    const template = document.querySelector('#solid-button-src');
    const clone = document.importNode(template.content, true);
    shadowRoot.appendChild(clone);
  }
});

This works in some browsers now, but nowhere near enough to make it production-ready. Your user can apply styles to solid-button, but they won't affect the content inside. If you have an up-to-date browser, you can see this in effect below.

Obviously this is not a solution for you now, but it might be the future.

customElements.define('solid-button', class extends HTMLElement {
  constructor() {
    super();

    const shadowRoot = this.attachShadow({
      mode: 'open'
    });
    const template = document.querySelector('template');
    const clone = document.importNode(template.content, true);
    shadowRoot.appendChild(clone);
  }
});
button {
  height: 100px;
  width: 100px;
  background-color: red;
  border: solid 1px black;
}

.class1 {
  height: 100px;
  width: 100px;
  background-color: blue;
}

my-button {
  background: red; /* does nothing visible */
}
<button></button>
<button id="id1" class="class1"></button>
<solid-button></solid-button>
<solid-button class="class1"></solid-button>

<template>
  <style>
    button {
      width: 100px;
      height: 100px;
      background-color: green;
      border: solid 1px black;
    }

  </style>
  <button>
    <slot name="content"></slot>
  </button>
</template>

1 Comment

great answer, even if its not right for me as you said. all: initial did the job
0

So I somehow made it work. Thanks for the answers.

all: unset and revert didnt work for me, all: initial did.

Furthermore i will give my internal classes very specific names. Like class=my-project-classto prevent external class-selectors from injecting their own attributes.

Also this should not work in IE.

See this Fiddle: https://jsfiddle.net/Lvxxnh8r/13/

2 Comments

Also in this fiddle of mine: jsfiddle.net/Lvxxnh8r/14 all: unsetworks fine. In this fiddle someone postet: jsfiddle.net/Lvxxnh8r/10 it doenst. I'm very confused.
I know why: the comments // Firefox and so on broke it
0

See this fiddle for an easy example. Unfortunately, the first selector sets the border on my blue element.

The reason the border is being defined on the second box is because it is a button, which is where you defined the border. That's how CSS works. If you don't want the border on your second element, you need to either define border: 0; on the second element, or in the original selector defining the border, button, use something that excludes the second box, like button:not(#id1).

4 Comments

as I said I have no influence on the first selector and what attributes its specifies. For example it could set a padding or anything else. I wouldnt know it even exists, because i dont know the website my snippet gets injected into, like google maps snippet. It can be applied anywhere. I am looking for a way to prevent external css to affect my elements.
If the CSS is loaded on the page, you can't keep it from affecting your elements. Best you can do is not load the CSS or remove the stylesheet or style tags via client-side code.
so you suggest using inline style and removing all classes via classList.remove or something similar?
Inline if you want, or you can just use !important. Using classList.remove will remove the classes from the elements themselves, which doesn't sound like your goal, but you can do that if it works for you. In the cases you provided, it wouldn't necessarily work, since in your fiddle, the global rule you want to remove isn't based on a class, it's based on an element name button. Modifying classList won't fix anything there. If style tags or a stylesheet out of your control are being added to your page, you can remove the style tag or stylesheet entirely, which will remove the styles.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.