Tag Archives: css

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>';

Advertisements
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

CSS absolute positioning prevents jquery ui droppable (sorta)

This is a case of too much drinking while coding for sure.

Working Example
I was trying to implement jquery UI draggables/droppables using the example here.
I made a couple of minor changes to the file to illustrate a point.

  1. I removed the class “ui-widget-header” from the “droppable” div because I wanted to make it a transparent box.
  2. I added “border-style: solid; border-color: red” to droppable so you could still see the box boundaries.

So you can see the results of my edit here in the starting positions of the draggable and droppable.

Image

Next, I moved the draggable box into the droppable box like so:

Image

So far so good. Finally, I drag the draggable outside of the droppable.

Image

 

Alright, looks good to me.

Absolute Positioning F*’s things up (sorta)

Now, I make a minor change to the droppable css again adding “position: absolute; left: 200px”.
“Position: absolute” positions it to an absolute position (duh). “left: 200px” just moves it away from the draggable, otherwise, it would show up right on top of it.

So again, let’s refresh our page and try again from the beginning here:

Image

Then we drag the draggable into the droppable like so

Image

Not bad.

And now let’s drag it out of the… damn it!

You can’t!

So absolute:positioning breaks draggables, right? Better report the bug, right?

Nope. Let’s put the “ui-widget-header” back on “droppable” removing its transparency so we can see what’s going on.

First, let’s remove “position:absolute” from the droppable’s css. And this time, we’re going to drag the draggable just slightly into the droppable, not all the way. It’ll look something like this.

Image

Now, let’s add back “position: absolute” to the droppable’s css, and do the same thing.

Image

Do you see what happened there?

When absolute:positioning is on, the draggable rests underneath the droppable. And because of that, you can’t grab it to drag it out of the droppable.

So we’ve confirmed it: it’s broken, right?

Not so fast.

The Solution

There’s this rarely used css attribute called z-index. This property specifies the layering order of stacked elements. (You didn’t know flat objects on a webpage had depth, did you?)

So we can set the z-index of the droppable to a negative number like -1, to bring the droppable behind the draggable. Or we can set the z-index of the draggable to a higher positive number like 10, to bring the draggable in front of the droppable.

 

Tagged , , , , ,