Making a background-image behave like an <img> tag

For this approach, there’s no css property to make a css background-image display inline like an image. We’re going to have to use JavaScript to position our image where we want it! If you haven’t written much JavaScript — you should start! It’s a fun and powerful way to add functionality to your site. We’re going to write our JavaScript using ES2015+ syntax, the latest standard of the language. To learn more about ES2015-ES2017 and more check out this presentation.

Let’s begin by comparing our original mobile design to the one from our previous example:

In the first example, our image is cropped and obscured. In the final implementation it stays true to the original.

In our first attempt, we crop the image so it covers all the available height. It seems like a good starting point for our background-image approach to preserve the aspect ratio of the background image. Once we get the image the correct size, then we can work on positioning it. Let’s give that a try.

We’re going to start this approach with similar code to our original example, but this time, we’re going to remove background-size: cover on mobile. Instead, we’re going to make the background image 100% wide and give it an automatic height to preserve it’s original aspect ratio, just like in our image-tag-to-background-image example. The code ends up looking like this:

and our example looks like this on mobile:

so close!

Already we’ve got a few things right:

Our image is the right proportions

Our content is padded correctly

We really just need to find a way to add more space above the content. Specifically, the space needs to be the height of the image. We could manually add a padding-top to the content, but this approach fails quickly. As soon as we resize the browser, our padding-top would no longer match the new dimensions of the image. What we really need is a way to dynamically set the padding-top of the content based on the current height of the image. Whenever your site needs dynamic values, it’s usually JavaScript to the rescue!

For simplicity’s sake, pretend our JavaScript is in either an included app.js file or an inline <script> tag positioned before the closing </body> tag on our page. We’re going to start by creating variables for our sections. Since our page might have multiple .c-sections , we’re going to write code that will correctly resize all of the background images. We’ll start by selecting all of our sections:

// Store all of our .c-sections in a variable called 'sections'

const sections = document.getElementsByClassName('c-section');

Now we have all of our sections as a list in one variable. Great! However, you may assume that this list is a JavaScript Array, but document.getElementsByClassName actually returns what’s known as an HTML Collection. We need to turn this collection into an array, which ES2015’s Array.from(...array) method makes simple! You can pass Array.from an HTML Collection, Node List, or other array-like structure and turn it into an array. Our list of sections now looks like this:

// Store all of our .c-sections in a variable called 'sections'

const sections = Array.from(document.getElementsByClassName('c-section'));

As we said previously, we want to run our code for each section, so we’re going to loop through our array using the forEach method, like

// Store all of our .c-sections in a variable called 'sections'

const sections = Array.from(document.getElementsByClassName('c-section')); sections.forEach(section => {

// do stuff in here

});

Great! Now we’re ready to write our logic to grab the background image from each section, detect its height, and apply that height as padding-top to the section. To do this, JavaScript needs to know the dimensions of our image. We’ll need to get the image url from the background-image css property on our .c-section . We can get the values of all css properties on an element by using the window.getComputedStyle method in JavaScript. To get the value of a single css property, we can follow our call of getComputedStyle with a call to getPropertyValue('background-image') . The whole thing ends up looking like this:

// Store all of our .c-sections in a variable called 'sections'

const sections = Array.from(document.getElementsByClassName('c-section')); sections.forEach(section => {

// Assign the background-image value to the variable 'image'

const imageUrl = window

.getComputedStyle(section)

.getPropertyValue('background-image')

});

If we run this JavaScript on our section, the value of the imageUrl variable will be url(“https://www.dropbox.com/s/xm1fohp06rfh1zd/2337770b75e90edc80cbe42d34c3c2bd-xxlarge.jpg?dl=1") . This is close to what we want, but look at the output. The permalink to the image is wrapped in the url(" ") text required by CSS. We could use JavaScript’s string.replace() method to replace the url(“ and ") pieces. This would look like this:

// Store all of our .c-sections in a variable called 'sections'

const sections = Array.from(document.getElementsByClassName('c-section')); sections.forEach(section => {

// Assign the background-image value to the variable 'image'

const imageUrl = window

.getComputedStyle(section)

. getPropertyValue('background-image')

// Remove 'url("' and ')' from the image url string

.replace('url("', '')

.replace('")', '')

});

This works but there’s another problem. In css, you can write url() with double quotes, like above, but also with single quotes, or even no quotes! All of the following are valid syntax:

background-image: url(http://image.com)

background-image: url('http://image.com)'

background-image: url("http://image.com")

To support these three cases, we’ll follow some simple steps:

Get the string between the first 4 characters:

url( and the last character ) . Remove every single or double quote in the url

Will handle this with JavaScript’s slice and replace methods. Our final JavaScript for this will look as follows:

// Store all of our .c-sections in a variable called 'sections'

const sections = Array.from(document.getElementsByClassName('c-section')); sections.forEach(section => {

// Assign the background-image value to the variable 'image'

const imageUrl = window

.getComputedStyle(section)

. getPropertyValue('background-image')

// Get the piece of the string starting after the 4th

character and ending with the 2nd to last character.

// Then, replace all occurrences of ' or " with a blank

string.

.slice(4, -1).replace(/["|']/g, "")

});