Monthly Archives: March 2017

The power of Shadow DOM

I recently had to inject another site’s webpage into a div in our own site. Back in early 2000, you’d use something like an but this is 2017.The requirements are the following:

  1. Pull the html source of the other site’s webpage
  2. Display it in our own webpage
  3. Make sure all styles are applied
    1. Ensure that styles don’t spill over to our own page’s DOM

Requirement 1: Pull the html source of the other site’s webpage

If you’ve done any web programming in the last decade, you know that simply pulling the html from another site from the frontend javascript is a big no-no, and blocked by cross-site-scripting restrictions. The trick is to have the backend webserver fetch the data and send it to the frontend. In a way, you’re proxying the data. This is a lesson for another time and not the focus of this post.

Requirement 2: Display it in our own webpage

This is actually pretty trivial once your backend webserver sends you the data. If you’re using node, make sure you’re “trusting” the source using $sce.trustAsHtml(htmlString).

Requirement 3: Make sure all styles are applied

But once you do this, you’ll soon realize that while the content is shown, the styling is missing. That’s because the .css files aren’t being fetched, and there’s really no good way of doing that.

You could parse the html and manually fetch the .css. But you’ll run into another problem. That site’s css now conflicts with your own site’s css and you get some weird mixup of styles.

If only there was a way to fetch the css and restrict it to the specific subtree of the DOM…

Shadow DOM

Here’s where this new (yet to be official) W3C standard comes in. As of this writing, Shadow DOM is only supported on Chrome 53.0+ and Safari 10.0+, and Android Webview 53.0+.

The idea is that you can create a subtree within the DOM, but it’s a special shadow subtree. What makes it special is that you can restrict css to just within this DOM.

Why is this such a big deal? Well, it solves the problem at hand. But it also solves a much more general problem.

Have you ever added an id attribute in a page only to find that you or someone else created that same id value on another page? That wasn’t such a big deal back in 2010, but many popular frontend web frameworks (e.g. angularjs, backbone)  consolidate all your pages into one and routes between them. What that means is that id’s can conflict. Even class-based css styles can conflict between two pages (how often have you created a class=”value”, no? just me?)

Anyways, Shadow DOM creates a true separation of DOM subtrees, meaning developers can build webpages as individual modules and not worry about conflicting id’s, classes, and styles. And with websites getting increasingly more complex, a finer more modular approach is needed.

Shadow DOM isn’t official yet, but I would bet my right arm that it will be.

Here’s some angular code to see how simple it is in action.

<div id="shadowSubtree"></div>
...
var shadow = angular.element('#shadowSubtree')[0].attachShadow({mode:'open'});
shadow.innerHTML='<link type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"></link><a class="btn">Bootstrap styled button</a>';

Tagged

When you need things to line up

Suppose you have the following html

<div class="container">
  <div class="thing"></div>
  <div class="thing"></div>
  <div class="thing"></div>
</div>

If you want things to line up horizontally, you could use a tried and true method

.thing {
    float:left;
}

But if the width of the container is not big enough, these things will wrap to the next line.

e.g.

.container {
    width: 50px;
}

Sometimes, you want them to line up and then just cut off when the container ends. For these cases, substitute it with these settings.

.container {
    white-space: nowrap;
}
.thing {
    display: inline-block;
}

If you actually wanted to see the rest of the things, then you could add a horizontal scroll bar

.container {
    overflow-x: scroll;
}
Tagged