3

I've developed an instant messaging component using AngularJS that adds instant messaging functionality to any web page. The component is fairly complex it's style sheet runs to about 800 lines.

I'm having a problem when the component is deployed to third party websites. Sometimes the CSS from the host website affects the styles of the chat widget.

Login and sign up buttons made upper case

The screenshot is used when the component is added to a fresh Wordpress install. You can see that the button text is overridden by the Wordpress style to be upper case.

The problem is this component will be deployed to tens of thousands of websites so it wouldn't be practical to solve each small issue on a case by case basis. It would also be impossible to know if these changes would have a knock on affect to another website.

The approach I'm currently considering is to create a very comprehensive reset stylesheet - I'd override all possible styles on all elements. That would give me a fresh canvas to start with.

This seems like a pretty onerous task so I was wondering if anyone had devised a better solution?

Note:

An iFrame isn't possible because the chat has to overlay the original web page

James Andrews
  • 3,257
  • 3
  • 31
  • 45
  • Another though I had was to write a CSS extractor that would traverse the DOM and pull out all the styles for each element. Then write it all to an external CSS file. – James Andrews Sep 25 '14 at 10:48
  • The only trick I can think of is to set `!important` on every rule. – Polynomial Sep 25 '14 at 10:50
  • I've tried setting !important on all my styles but that doesn't solve the problem of when there are styles I've not set i.e. button { text-transform: uppercase; } I think if I made a big reset style, it would take priority because I'd prefix each style with the base ID of my component. – James Andrews Sep 25 '14 at 10:53
  • 2
    Could you explain the difficulties with using an `iframe`, because it sounds like you're putting it in some kind of modal/draggable component, which is absolutely do-able with an iframe... – David Thomas Sep 25 '14 at 10:55
  • Here's a link to the project http://chatcat.io/ as you'll see, the boxes have to be able to overlay the host website. So it would be possible to set the iframe full screen but then you'd have to be able to pass the clicks through the iframe so the user could still interact with the host website. – James Andrews Sep 25 '14 at 10:59
  • I don’t see what would prevent the use of an iframe, even when looking at the page you just mentioned. Each of those boxed widgets looks pretty stand-alone. And what you mean by “overlaying” and passing through clicks I can’t see there either – at least not in a way that would present a significant difference between using an iframe to encapsulate the content, or having it reside in the parent page’s DOM directly. – CBroe Sep 25 '14 at 11:06
  • I hadn't thought of that but I don't know how it would work with Angular - would angular be able to access the various iframes? – James Andrews Sep 25 '14 at 11:22
  • @BenSmiley What's wrong with overriding the WordPress CSS? – MiniRagnarok Sep 25 '14 at 13:11
  • There's no problem but each host website causes different issues. I could fix it in this case easily but I need a solution that will be bulletproof for up to 100k websites. – James Andrews Sep 25 '14 at 13:23

2 Answers2

2
  • namespace your classes to avoid any possible clashes
  • reset all styles (super tedious I agree)

if you really want to go hardcore, I would not recommend any of the below but they are available options:

  • use !important
  • use inline styling with the above
Luca
  • 9,259
  • 5
  • 46
  • 59
  • I've tried using !important but as I mentioned above, some styles still leak in since I've not defined a style for every attribute / element combination. Inline styles isn't really an option because of the complexity of the component. – James Andrews Sep 25 '14 at 11:03
  • 1
    Using !important or inline-styling should not be in anyone's answer. The only time I ever have to use !important in production code is when some plugin maker has decided to use !important on all of their code and it's overriding my site's styling. – MiniRagnarok Sep 25 '14 at 13:09
  • @miniRagnarok I wish you could read the full answer before commenting, where I said 'I would not recommend any of the below' referring to `!important` - I despise its use the same way as you, but in the SO case it DOES enforce its styling to be respected (together with reset settings on all properties). Tedious and bad practice as much as you want, but the answer makes sense and the downvote seems inappropriate the least – Luca Sep 25 '14 at 14:04
  • @Luca I have no ill-will towards you. I even note in my answer that your suggestion to use namespaces is the correct answer. However, you did state "I would not recommend any of the below except from the specific case you have". Which is wrong. – MiniRagnarok Sep 25 '14 at 14:06
  • @Luca If you had said "I don't recommend the following:" and left is there, I would have upvoted you. – MiniRagnarok Sep 25 '14 at 14:07
  • surely, I'm not saying that you have ill-will towards me. criticism is part of learning! If it's the wording that is making you feel that my answer is not correctly formulated, you could have suggested an edit? I'd been very happy for that to happen – Luca Sep 25 '14 at 14:14
2

Like Luca suggested, using a namespace is the correct answer.

While you could use !important or an iframe I dislike both of those answers and here's why.

Why you shouldn't use !important

  1. Your goal is to create CSS that can't be overridden. Using !important doesn't actually solve that problem. I could still override your styling by using the same specificity that you have. It is however, a pain to do.
  2. Mozilla specifically recommends that you don't do it.
  3. As you've said yourself, this could be used on 100k+ websites. The likelihood that you're going to override someone else's styling is pretty high. Using !important is going to ruin their day. You've effectively taken the cascading out of CSS. As a rule, use the least amount of specificity that you can comfortably get away with. This makes everyone's life easier.

Why an iframe is not the answer

I'm not nearly as opposed to using an iframe as I am to using !important but there is some negatives that you need to be aware of.

  1. iframes give control to you (the plugin maker) at the cost of the user. e.g. The user has no choice in being able to match your iframe's responsiveness with their site. It's entirely likely that some user is going to have a specific breakpoint that isn't going to play nice with your plugin.
  2. Your styling is impossible to override. This point could be seen as a positive for you but I find that it's a negative to the user. Being able to style the colors of your plugin helps make the plugin a part of the site. It's a guarantee that your plugin's colors won't mesh well with some sites. Letting the user change the colors is a must for me.

Using Namespaces

The idea is pretty simple. Let's say that your app is called SuperIM2000. All you do is make sure that there's a container with the same class name and that you use it to target your styling. This has the added benefit of allowing you to use very simple class names e.g. button.

HTML

<div class="superIM2000">
    <input class="button" />
</div>

CSS

.superIM2000 .button{
    color:#000;
}

As you can see, the specificity is very low. However, the likelihood that you're going to override someone else's styling is extremely low. This has a benefit to the user as well. It's possible that the button class is already used in their site and it can take advantage of any inheritance that you haven't overridden.

MiniRagnarok
  • 959
  • 11
  • 23
  • This is what I've ended up doing - I'm taking a good base style (in this case UIKit) and name spacing it to my app. This stops the styles sheets affecting the host site and provides a reasonable baseline for the styles for the app. – James Andrews Sep 25 '14 at 15:12
  • what about using `!important` *inside* a namespace or a [scoped css block](https://css-tricks.com/saving-the-day-with-scoped-css/)? would that still frowned upon? – woojoo666 Nov 05 '15 at 23:02
  • 1
    @woojoo666 Sorry for the late response I've been out with the flu. Yes it's still frowned upon to use !important inside a namespace. Its primary use is a debugging tool. There are other valid uses but they're rare. For example, it's the only way to override inline styles. As for scoped css blocks, I don't think they have the support required to use them myself. http://caniuse.com/#feat=style-scoped – MiniRagnarok Nov 11 '15 at 14:29