• Home New Posts Forum List Trending New Threads New Media Spy
  • WikiPost Latest summaries Watched WikiPosts
  • Support FAQ and Rules Contact Us

Safari not computing image aspect ratios from width and height attributes

  • Thread starter sulliops
  • Start date Mar 30, 2021
  • Tags ios ios 14 macos macos 11 safari safari 14 webkit
  • Sort by reaction score
  • Web Design and Development

sulliops

macrumors newbie

  • Mar 30, 2021

I've recently implemented a lazy image loading feature on an image-heavy website, and have been having issues with reflow. I fixed the problem by manually specifying the image dimensions using the `width` and `height` image attributes, as below: Code: <img class="lazyload img-fluid" data-src"/path/to/image.jpg" width="200" height="400" /> It works great in every browser except Safari, but I'm confused because Safari 14 supposedly supports computing aspect ratios based on the `width` and `height` attributes . None of my up-to-date macOS or iOS devices seem to recognize this feature in Safari, but they do in every other modern browser. The expected outcome is that the spot on the page where the `<img />` tag is located should be reserved (painted) based on the calculated aspect-ratio using the `width` and `height` attributes, to be later replaced by the `data-src` attribute via the lazy-loading plugin. In Firefox and Chrome (+ Chromium-based browsers), the space is reserved until the image is loaded (to prevent reflow); in Safari, the space is not reserved and the page shifts after the image is loaded. Here's a CodePen example with near identical code to mine (you should open in Safari and click immediately on "Nav 4" to see the issue): https://codepen.io/sulliops/full/QWdwRxx Here's a screencap of my issue: https://gyazo.com/da76046282965f7a32ed3d85cc7423df Anyone have any clue as to what I'm doing wrong? I'm not worried about backwards compatibility (Safari doesn't support the feature in question before 14.0) or IE support, so this solution is perfectly fine for me until `aspect-ratio` becomes available in browsers other than Chrome. Safari is important, though, so I'll take any suggestions.  

arn

macrumors god

Hmm... the images on the front page are lazy loaded, and is working properly in saving the space. Let me look at your code a bit more closely.  

arn said: Hmm... the images on the front page are lazy loaded, and is working properly in saving the space. Click to expand...

I figured it out I think. You need a non empty "src" for Safari to calculate the size. try adding src=" https://images.macrumors.com/images-new/1x1.trans.gif " to your <img> html arn  

arn said: I figured it out I think. You need a non empty "src" for Safari to calculate the size. try adding src=" https://images.macrumors.com/images-new/1x1.trans.gif " to your <img> html arn Click to expand...
sulliops said: Wow, that is beyond inefficient — but it worked in the CodePen. Actually applying that fix on my production website didn't do much good, though — it actually broke compatibility with other browsers, including Safari, and the reflow issue is back in full swing. Any ideas? Click to expand...
  • Barry Pollard
  • Updated Jan 11, 2022

Setting Height And Width On Images Is Important Again

  • 18 min read
  • Browsers , Performance , Optimization , Core Web Vitals
  • Share on Twitter ,  LinkedIn

About The Author

Barry Pollard is a web developer who is obsessed with web performance. He is the author of the Manning book “ HTTP/2 In Action ” and is a one of the maintainers … More about Barry ↬

Email Newsletter

Weekly tips on front-end & UX . Trusted by 200,000+ folks.

Web performance advocates have often advised to add dimensions to your images for best performance to allow the page to be laid out with the appropriate space for the image, before the image itself has been downloaded. This avoids a layout shift as the image is downloaded — something Chrome has recently started measuring in the new Cumulative Layout Shift metric .

Well, a dirty, little, secret — not that well-known outside the hard-core web performance advocates — is that, until recently, this actually didn’t make a difference in a lot of cases, as we’ll see below. However, adding width and height attributes to your <img> markup have become useful again after some recent changes in the CSS world, and the quick adoption of these changes by the most popular web browsers.

Recommended Reading

The CSS contain property gives you a way to explain your layout to the browser, so performance optimizations can be made. However, it does come with some side effects in terms of your layout. Read a related article →

Why Adding Width And Height Were Good Advice

Take for example this simple page:

This might render in two stages, first as the HTML is downloaded, and then second once the image is downloaded. With the above code, this would cause the main content to jump down after the image is downloaded and the space needed to display it can be calculated:

Layout shifts are very disrupting to the user, especially if you have already started reading the article and suddenly you are thrown off by a jolt of movement, and you have to find your place again. This also puts extra work on the browser to recalculate the page layout as each image arrives across the internet. On a complex page with a lot of images this can place a considerable load on the device at a time when it’s probably got a lot of better things to deal with!

The traditional way to avoid this was to provide width and height attributes in the <img> markup so even when the browser has just the HTML, it is still able to allocate the appropriate amount of space. So, if we change above example to the following:

Then the render happens like below, where the appropriate amount of space is set aside for the image when it arrives, and there is no jarring shift of the text as the image is downloaded:

Even ignoring the annoying impact to the user in content jumping around (which you shouldn’t!), the impact on the CPU can also be quite substantial. The below screenshot shows the performance calculations performed by Chrome on a site I work on which has a gallery of about 100 images. The left-hand side shows the calculations when width and height are provided, and on the right when they are not.

As you can see, the impact is considerable — especially on lower-end devices and slow network speed, where images are coming in separately. This increases load time by a noticeable amount.

How CSS Interacts With Element Widths And Heights

Widths and heights on an image can cause issues when you try to alter them using CSS. For example, if you want to limit your images to a certain width you might use the following CSS:

This will override the width of the image and constrain it when necessary, but if you have explicitly set the height on the image tag, then we are not overriding that (only the width) and you will end up with a stretched or squashed image, as we have no longer maintained the aspect ratio of the image:

This is actually very easily fixed by adding a height: auto line to the CSS so the height attribute from the HTML is overridden too:

However, I find it still catches people by surprise and sometimes leads to them not specifying image dimensions in the HTML instead. With no image dimensions, you can get away with just specifying max-width: 200px in the CSS without having to specify height: auto and the browser will automatically figure out the height itself — once it has the image.

So, once we add the dimensions and that the height: auto trick, we get the best of both worlds, right? No layout shifts, but also the ability to resize images using CSS? Well until very recently you might have been surprised to find out the answer was in fact: no ( I was — hence why I decided to write this article).

For example, take the code below:

This would have resulted in this load:

Wait, what’s going on here? We’re back to the first problem. I thought I said that by specifying the image dimensions in the HTML you could avoid this layout shift problem? Well, this is where it gets interesting and will lead on to the main point of this article.

The problem is that, unless you were giving explicit width and height CSS values to your images — and who wants to limit themselves like that in a responsive world where you want the image to expand or shrink to fill up the available space — then CSS will need the dimensions from the image file itself to figure out the auto part of the dimensions. It ignored any width and height attributes set in the HTML.

The implication of all this is that specifying width and height attributes on images often wasn’t actually that useful in a lot of cases. Yes, when an image is being shown at full size, without any CSS changing any dimensions, it is useful to resolve the layout shifting problem. However, when you use CSS like below to ensure images do not overflow their available space, then you run into problems as soon as the available width becomes smaller than the actual image size.

This affects any page where we constrain the image size in a responsive manner — i.e. small screen mobile devices. These are likely to be the very users suffering with network constraints and limited processing power that will suffer most from layout shifts! Of course, we ideally should be delivering appropriately sized images for the screen size, but you cannot cover every device size, so often images will need some resizing by the browser, particularly on mobile.

Many websites may not bother to specify width s and height s on their <img> tags. That could be because they weren’t aware this was useful, or because they were all too aware of what we talked about here and knew it actually wasn’t that useful in a lot of cases. Whatever the reason is beside the point, they are frequently not provided. (How can we even evangelize putting the effort into using them given what I’ve just described?) Even the popular Lighthouse auditing tool doesn’t flag when you don’t do this (though in light of some of the things we’re about to talk about, that is under discussion again ).

Working Around The Problem

The limitations for responsive images have been known for a long time and many workarounds, including the so-called padding-bottom hack , have been created to work around the issue. This uses the fact that padding percentages (including padding-bottom ) are always based on the container width (to ensure a consistent padding even if height and width differ). This fact can therefore be used to create a container with where the height is set based on a ratio of the width. For example for, let’s say we have an image with an aspect-ratio of 16:9, then the following CSS code will create the appropriately sized space for the image:

The three main downsides of this technique are the following:

  • It requires a hard-coded ratio to be calculated ( 56.25% — 9÷16 — in this example), so it potentially requires custom CSS for each different image.
  • The CSS code is not exactly easy to remember — forgetting or removing a single line of the above CSS code will break the whole thing. Not to mention this technique requires all images to be wrapped in an extra container element.
  • This is a more advanced technique that not all web developers know about or use.

And, let’s be honest — it’s a bit of a hack! So, we really should fix this properly, shouldn’t we?

Fixing The Resizing Problem

The issue has been tackled from a few different directions by a number of different standards organizations.

The CSS Working Group (CSS WG) proposed the aspect-ratio property that Rachel wrote about previously . This would tackle the complexity problem (issue 2) once it becomes available, and simplify the above code to just this:

Much nicer! This is particularly useful for video where we usually have a set number of commonly used aspect-ratios, so we could create a few classes like above for each size. It’s perhaps less useful for images where dimensions are much less standardized, as it doesn’t solve issue 1 (custom CSS code required per image), nor issue 3 (website developers will need to remember to set this). So, it’s a step forward, but not a full solution.

Separate to this, the Web Incubator Community Group (WICG) — a group of browser developers and other interested parties that can experiment on technologies to see if they work before formal standardisation — also created a proposal to fix this . They proposed the intrinsicsize attribute, that would look like this:

As this is an HTML attribute, it can be set per image (solving issue 1), and is relatively easy to code (solving issue 2), but was still likely to suffer from adoption issues (issue 3) unless it became very well-known with a big push from the whole community.

We already have a common, well-known method of setting the width and height on <img> elements (even if they are not used as much as they should be!) so anything new, other than that, is going to suffer from the adoption issue. And that is where the (now seemingly obvious!) answer presented itself.

Jen Simmons proposed this elegant, and simple solution , that she had come up with, along with fantasai :

Rather than hard-coding the aspect-ratio , this uses the attr CSS function to create the appropriate aspect-ratio based on the image width and height attributes provided by the HTML. The attr function has been around for a while, but has been very limited in scope — it’s supported for content by all browsers , but not for the wider use case of any other attribute like width and height , which is what is needed here.

If attr was able to be used for the well-known width and height attributes from img elements, then it could use be used to automatically calculate the aspect-ratio as per above. This would solve issue 1 (no hard-coded aspect ratio needs to be set in the HTML nor the CSS), issue 2 (very simple to add) and, as we shall see, there is a very simple answer to issue 3 (adoption).

Basically, this solution means if the following four conditions are true, then the correct image dimensions could be calculated without needing to wait for the images to download, and so without the need of a content layout shift:

  • height is set on the element in HTML
  • width is set on the element in HTML
  • height (or width ) is set in the CSS — including using percentage values like max-width: 100%;
  • width (or height ) is set to auto in the CSS.

If any one of these were not set, then the calculation would not be possible, and so would fail and be ignored and have to wait for the image to be downloaded.

So once browsers support using the HTML width and height to calculate the aspect-ratio we can solve our problem very simply with no change in practice to HTML and one line of CSS code! As mentioned above, this is also something many web developers may have already assumed was happening anyway.

Driving Adoption Of This Solution

Because this is just a CSS attribute, the proposal contained a further twist — it could be added to the user-agent stylesheet used by browsers so would not even require any changes from web developers to benefit from this.

The user-agent stylesheet is where default CSS definitions are set (e.g. what font-size the h1 element uses), which can be overridden by your own CSS if you want. By adding the above aspect-ratio one-liner to this we don’t need to drive adoption — we basically turn it on automatically for all sites that meet the above four conditions!

However, this does depend on the attr function having access to the width and height HTML attributes, and also the upcoming aspect-ratio CSS property to be completed — neither of which has happened yet. So instead, as an easier fix, the browsers could implement the equivalent logic deep in rendering code rather than exposing it via the user-agent stylesheet, but the effect is the same. This alternative implementation approach was even suggested as part of the proposal .

Firefox went ahead and did this as an experiment and then turned it on by default for Firefox 71 . Once that was released, then your site may well have just got faster for free — thanks Mozilla! Maybe in future, they will move this to the user-agent stylesheet method, but for now, this is sufficient (and perhaps more performant?).

Backwards Compatibility

When introducing a change in behavior, there is always a concern about backwards compatibility and this feature was no different. In theory, as long as the four attributes were appropriately set, there should be no breakage with this.

However, when Firefox initially experimented with it, they discovered problems for those setting the width and height incorrectly in their HTML. Whereas previously these incorrect values would be ignored if the CSS overrode them, now they were being used when auto was set and the images were not displayed correctly and led to squished or stretched images. Now you could argue that web developers shouldn’t set these values incorrectly, and in some cases, it would be already broken even without this change (the case above when you didn’t set height: auto ), but still, breaking sites is never a good thing. That is also something the web tries very hard to avoid — and is mostly very good at avoiding that (it’s one of my favorite things about the web as a platform).

The solution to that problem, however, was relatively simple: have the actual image aspect-ratio of the image override any CSS calculated aspect-ratio. This way the (incorrectly) calculated aspect-ratio can be used for initial layout, but then can be recalculated when the image is downloaded, so the image is displayed as it was before. This does cause a layout shift (since the incorrect space was allocated initially) but that was happening before anyway, so it’s no worse. In fact, it’s often a lot better as an incorrect aspect ratio will often be closer to the truth than a zero aspect-ratio.

Rollout To Other Browsers

After Firefox’s successful experimentation, Chrome also decided to implement this (again using the layout coded method for now rather than default user-agent stylesheet), and rolled it out by default in Chrome 79 . This also took care of the other chromium-based browsers (Edge, Opera and Brave, for example). More recently, in January 2020, Apple added it to their Tech Preview edition of Safari , meaning it should hopefully be coming to the production version of Safari soon, and with that, the last of the major browsers will have implemented this and the web will become better and less jolty for a huge number of sites.

Limitations

There are a few limitations to be aware of with this feature, including issues with:

Art Direction

Lazy loading.

The fix works great to calculate the aspect-ratio based on a fixed width and height , but what about when those change? This is known as art direction and an example is shown below:

In this case we are using a wide image for desktop, and then a square, cropped image for mobile. Responsive images can be implemented with the picture element like this:

Currently, this only allows the width and height to be set once on the main, fallback <img> element and not on the individual <srcset> alternatives. Adding these has been proposed but until then, this is currently a limitation of the solution, and using images with different dimensions will still experience a layout shift.

Update (July 2021) : This was added in Chrome 90.

This feature would be perfectly suited for use with lazy-loading. Ideally, all lazy-loaded images are loaded off-screen as you scroll down the page before the lazy-loaded image enters the viewport, but often this is not the case depending on how fast the user scrolls and the network, so having the image area correctly set would at least avoid the layout shift after loading does occur. Additionally, even when loading is happening off-screen, layout shifts can be costly in terms of CPU time, as we have shown above.

However, lazy loading techniques may involve not using an <img> element, or at least one without a src (to prevent the browser from downloading the image by default). Therefore, it may not be able to benefit from this recent change depending on how your browser handles the element used or src -less <img> elements. Though if the CSS version of this solution becomes available, then website developers will have greater control over specifying aspect-ratio themselves.

Native lazy loading was recently released by the Chrome team and it has since been added to the HTML spec . Other browsers are also looking to support this with Firefox also getting this soon , and Safari hopefully not too much later . That does make use of the <img> element with a src with syntax like the following (including when used as part of the <picture> element):

Perfect! Well, unfortunately, I discovered this height and width solution is not compatible with the recently released native lazy-loading functionality as can be seen on this test page . I’ve raised a bug for this issue and hopefully the Chrome team will fix this soon. ( Update: This was fixed in Chrome 83. )

Currently, the browsers that have implemented this, have only done for the <img> element, but it would also be useful for <video> , <iframe> and <object> elements to name a few, and this under discussion . Again, if the CSS version of this technique becomes available through the attr functions and aspect-ratio property, then that puts the power in the website developer to implement this for whatever elements they want!

Update (Oct. 2021) : CSS aspect-ratio support was since added in Chrome 88, FireFox 89 and Safari 15 but not yet with the ability to set these via data attribute references.

I love improvements that just work without any effort required of website owners. That is not to ignore the hard work required by the browser developers and standardization teams, of course, but it’s often rolling out to websites that is the real difficulty. The less friction we can add to introduce these improvements, the more likely they will be adopted, and there’s no better friction than none at all! Fixing the impact of layout shifts on users for responsive images seems to be one such improvement and the web is all the better for it.

The one change that is required of us web developers is to ensure we are providing width and height attributes in our markup. It’s a habit we shouldn’t really have gotten out of, and many CMS and publishing tools make this relatively easy. I queried the HTTPArchive and it looks like 62% of <img> tags have width or heights , which is way higher than I expected to be honest — but let’s try to increase that statistic even more now we have a reason to again. So, I implore you to check that you are doing this on your sites and, if not, start to. It will improve the experience for your users and ultimately make them happier, and who doesn’t want that?

Further Reading

  • Performance Game Changer: Browser Back/Forward Cache
  • How To Hack Your Google Lighthouse Scores In 2024
  • The Era Of Platform Primitives Is Finally Here
  • How To Monitor And Optimize Google Core Web Vitals

Smashing Newsletter

Tips on front-end & UX, delivered weekly in your inbox. Just the things you can actually use.

Front-End & UX Workshops, Online

With practical takeaways, live sessions, video recordings and a friendly Q&A.

TypeScript in 50 Lessons

Everything TypeScript, with code walkthroughs and examples. And other printed books.

DEV Community

DEV Community

Maciej Trzciński 🌱🇵🇱

Posted on Dec 13, 2020 • Updated on Nov 29, 2021 • Originally published at Medium

100vh problem with iOS Safari

100vh

The web content it's outside the viewport although we used 100vh (the red opacity box with 100vh text).

The problem you have been receiving after adding the height: 100vh to mobile resolutions. It happens due to the calculation method which Safari and Chrome are using. Mobile devices calc browser viewport as ( top bar + document + bottom bar ) = 100vh . I had a hard time with 100vh when the page have to have a section filled the whole screen. After a couple of hours, I've found the solutions that I show you.

They are two solutions, the first needs JavaScript and CSS, the second solution required only CSS.

1. JS & CSS solution

Let’s get started first with the JS file:

appHeight function has sets new style property var( --app-height ) including current window height, --app-height it is necessary for next steps.

In the previous step I've created the reference --app-height , wrapping in the var() I've received CSS variable var(--app-height) . This variable is allowed to read values created by JS.

2. CSS solution (not recommend)

The last, but not the least solution is --webkit-fill-available , this solution works only on Apple devices, it won't solve the problem on Android devices. I don't recommend this solution, but it's worth showing.

Thank you for your attention! I’ll appreciate your feedback.

If you like this article, follow me on Twitter @MaciejDEV

Top comments (13)

pic

Templates let you quickly answer FAQs or store snippets for re-use.

iway1 profile image

thanks this is pretty easy. It's important to mention you'll want to run this on window resize events if you intend to allow your users to resize

fabiogiolito profile image

  • Location Lisbon, Portugal
  • Work Designer at Expa
  • Joined May 19, 2019

My approach is to disable the show/hide of the safari bars by preventing the body from scrolling. That way the content area height is constant.

maciejtrzcinski profile image

  • Location Poznań, Poland
  • Work Front-End Developer at Tonik
  • Joined Jun 12, 2020

Hi, It will work, but you have to remember about for example scrollTo and #anchors in this solution.

davidhbeck profile image

  • Joined Jul 24, 2017

nice! thanks for posting, this is the most effective solve I've found.

something thing I noticed after implementing this solution is that it can trigger the fabled 'jumpy scroll', referenced in the stack overflow post I'm sure we all landed on before finding this post. stackoverflow.com/questions/371122...

as a workaround I created two css variables, one for the fixed "starting" height, and another "dynamic" height that is only used for the shopping cart, mobile menu and other fixed-position elements that require 100% screen height.

pasted below in case someone else runs into the same issue!

// set up css var for starting app height. this will not change on resize so we can avoid the jumpy scroll issue const appHeight = () => { const doc = document.documentElement; doc.style.setProperty('--app-height', ${window.innerHeight/10}rem ) }; window.addEventListener('orientationchange', appHeight); appHeight();

// set up css var for dynamic app height. this is just for the cart and mobile menu since they need to be fixed to size at all times.

const dynamicAppHeight = () => { const doc = document.documentElement; doc.style.setProperty('--dynamic-app-height', ${window.innerHeight/10}rem ) }; window.addEventListener('resize', dynamicAppHeight); dynamicAppHeight();

jochenthomas profile image

  • Joined Jan 20, 2021

Hi, see: dev.to/admitkard/mobile-issue-with... Same issue, but again - on current Safari it is NOT working! Even on Android devices, I see the same issue.

So is there a working solution if the address bar moves away (no resize/switch to landscape etc.).

chrisjayden profile image

  • Location Enschede, NL
  • Work Entrepreneur at self-employed
  • Joined Dec 8, 2020

I’m confused 🤣

So what are you saying? That the JS solution in this thread doesn’t work but the one you linked does?

mrvaa5eiym profile image

  • Joined Sep 18, 2019

Hi could you please also illustrate the problem? thanks!

Hi clivend,

Yes, sure I will illustrate the problem today/tomorrow. Thanks for letting me know what is missing!

kieransweeden profile image

  • Joined Sep 22, 2021

This majorly helped with a college project of mine, thank you for writing this!

ipscodingchallenge profile image

  • Email [email protected]
  • Location France
  • Education Self Taught
  • Work Junior Full Stack Developer
  • Joined Jul 3, 2020

Actually, it's not only on safari. I had the exact same problem on chrome / brave and used the first solution for one of my latest projects ;)

Hi ips-coding-challenge,

yes, you are right, I missed issue with OnePlus what I had last year. 🙏

wyn153 profile image

  • Joined Apr 10, 2023

magnetism profile image

  • Work Agency Owner
  • Joined Jan 2, 2023

But how to set for only one page? This solution applies to all pages.

Thanks again.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink .

Hide child comments as well

For further actions, you may consider blocking this person and/or reporting abuse

farheen_sk profile image

Dev.to 6-Series: How to get started on writing code

Farheen Shaikh - Aug 10

eusisaku profile image

spreadsheet/excell-js-css

eusisaku - Aug 9

anmolbaranwal profile image

How to Build Frontend Apps 10x Faster

Anmol Baranwal - Sep 5

maria_isham_a842814b9884e profile image

Optimize School Management with Advanced Attendance Tracking Software Solutions

Maria Isham - Sep 4

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

w3docs logo

  • Password Generator
  • HTML Editor
  • HTML Encoder
  • JSON Beautifier
  • CSS Beautifier
  • Markdown Convertor
  • Find the Closest Tailwind CSS Color
  • Phrase encrypt / decrypt
  • Browser Feature Detection
  • Number convertor
  • CSS Maker text shadow
  • CSS Maker Text Rotation
  • CSS Maker Out Line
  • CSS Maker RGB Shadow
  • CSS Maker Transform
  • CSS Maker Font Face
  • Color Picker
  • Colors CMYK
  • Color mixer
  • Color Converter
  • Color Contrast Analyzer
  • Color Gradient
  • String Length Calculator
  • MD5 Hash Generator
  • Sha256 Hash Generator
  • String Reverse
  • URL Encoder
  • URL Decoder
  • Base 64 Encoder
  • Base 64 Decoder
  • Extra Spaces Remover
  • String to Lowercase
  • String to Uppercase
  • Word Count Calculator
  • Empty Lines Remover
  • HTML Tags Remover
  • Binary to Hex
  • Hex to Binary
  • Rot13 Transform on a String
  • String to Binary
  • Duplicate Lines Remover

How to Fix CSS Issues on Safari

Different browsers serve the web page content differently which can cause problems while using some CSS properties. To solve this kind of issues, there is a simple solution that will help you with 90 percent of cases.

Although many programmers face some difficulties when Safari doesn’t support CSS properties, these properties work fine in other browsers.

Displaying properties in Safari

There is a CSS appearance property used to display an element using a platform-native styling based on the users' operating system's theme. To make it work on Safari, we must set the appearance property to its "none" value. Also, use -WebKit- and -Moz- vendor prefixes.

Let’s see an example, where we use this trick to make the border-radius property work on Safari without any problem.

Example of making the border-radius property work on Safari:

The background-color property may also have the cause problem on Safari. Let’s see one more example.

Example of making the background-color property work on Safari:

Related resources.

  • CSS appearance Property
  • HTML Basics
  • Javascript Basics
  • TypeScript Basics
  • React Basics
  • Angular Basics
  • Sass Basics
  • Vue.js Basics
  • Python Basics
  • Java Basics
  • NodeJS Basics

Avoiding <img> layout shifts: aspect-ratio vs width & height attributes

By default, an <img> takes up zero space until the browser loads enough of the image to know its dimensions:

When you run the demo, you'll see the <figcaption> immediately. Then, after a few seconds, this paragraph and subsequent page content shifts downwards to make room for the image. This makes the user experience massively frustrating, as content moves out from under the user's eyes/finger/pointer.

For over a decade, we had to use silly hacks to manually apply an aspect ratio, and then, bloody typical, two better solutions arrived at roughly the same time. They are CSS aspect-ratio , and width & height presentational hints.

So, which should you use? First, let's take a look at how the features work, as there's quite a bit of misinformation out there…

CSS aspect-ratio

If you do this:

…you get this:

This feature became cross-browser compatible once it landed in Safari 15, late 2021, having arrived in Chrome & Firefox earlier that year.

It works on any element, but here's a demo with <img> :

This time, the image reserves space for its content as soon as it appears in the document, so stuff doesn't shift around once it loads.

The other solution is…

Width & height presentational hints

If you set dimensions on your image:

And set height to auto :

…the image will have an aspect ratio applied, even before it loads.

This landed in Chrome and Firefox back in 2019, and became cross-browser compatible when it landed in Safari 14 a year later. So, this feature has been around a little longer than CSS aspect-ratio .

In addition to <img> , this feature also works on <video> and <input type="image"> .

Update: Although browsers implemented the feature for <video> as per the spec, the spec is broken , so it doesn't work in practice.

However, there's a bit of misinformation floating around…

No, this doesn't use attr()

A lot of articles say this feature works via a user-agent stylesheet like this:

This isn't how it actually works

Firstly, this feature doesn't work on embed , iframe , marquee , object , or table . But also, this usage of attr() wouldn't work in practice because it returns a string. To make it work properly, you'd need to cast the attribute to a number, which CSS supports!

This isn't how it works either

But this isn't how it works, because:

No browser supports attr on all properties

…no browser supports attr() , aside from very particular cases like content on pseudo-elements. Hopefully that will change one day!

How does it actually work?

Here's what the spec has to say:

The width and height attributes map to the aspect-ratio property (using dimension rules) on img and video elements, and input elements with a type attribute in the Image Button state. — Attributes for embedded content and images - HTML

So, it does map to the aspect-ratio property. Specifically:

…the user agent is expected to use the parsed dimensions as a presentational hint for the 'aspect-ratio' property of the form auto w / h . — Mapping to aspect-ratio - HTML

You can think of a "presentational hint" as something a bit like a zero-specificity inline-style that's applied internally.

This uses a feature of aspect-ratio I didn't mention earlier:

The new bit is auto . Here's what the spec says:

If both auto and a <ratio> are specified together, the preferred aspect ratio is the specified ratio of width / height unless it is a replaced element with a natural aspect ratio , in which case that aspect ratio is used instead. — CSS-sizing level 4

A lot of articles gloss over this, probably because the spec text is a little hard to read, but it adds an important bit of behaviour:

An <img> is a "replaced element", but it doesn't have a "natural aspect ratio" until the browser has loaded enough of the image to know its real width & height. That means the 16 / 9 bit is ignored once the browser has the real data from the image. This doesn't usually matter, because the result is the same. But, let's say I got the width and height wrong:

The browser will use an presentational hint of aspect-ratio: auto 4 / 3 , but the image is actually 16 / 9 . Here's what happens:

When the image is added to the page, it takes up the 4 / 3 area I specified. But once it loads, the auto rule kicks in, and the browser corrects the aspect ratio to 16 / 9 .

Compare this to the behaviour of:

Without auto , the <img> remains 4 / 3 , and the image appears stretched. You can avoid the stretching with object-fit :

In this case, parts of the image are cropped. Oh, one more thing:

A slight issue in Firefox

Responsive images let you provide different images to use at different widths:

In this case, the two images have different aspect ratios. Chrome and Safari use the correct width and height depending on which source is used, but Firefox will always use the dimensions from the <img> , resulting in a content shift when it realises the calculated aspect-ratio is incorrect.

Here's the Firefox bug to track this. Hopefully it'll get fixed soon!

So, which method should we use?

Ok, until now the article has been a massive side-quest. Now we're at the actual point. And, in my opinion, the answer is… nothing new.

We've got one solution, aspect-ratio , which is CSS-based. And the other solution, presentational hinting, which uses width and height attributes. The question is very similar to "should this image be a <img> or a CSS background-image ?" and the answer is the same: Is it content or design?

If I'm adding an image to an article on my blog, that's content. I want the reserved space to be the aspect ratio of the content. If I get the width and height attributes wrong, I'd rather the correct values were used from the content image. Therefore, width and height attributes feel like the best fit. This means I can just author content, I don't need to dip into inline styles.

If it's a design requirement that the layout of an image is a particular aspect ratio, enforcing that with aspect-ratio in CSS can be appropriate. For example, a hero image that must be 16 / 9 – if the image isn't quite 16 / 9 I don't want it messing up my design, I want the design to take priority. Although, if the image isn't actually that aspect ratio, it'll either end up stretched ( object-fit: fill ), letter-boxed ( object-fit: contain ), or cropped ( object-fit: cover ). None of which are ideal.

You could use aspect-ratio and media queries to make up for the lack of support in Firefox when it comes to <picture> and art direction. But, I'm hoping that they'll fix that bug sooner rather than later, so we don't need to hack around it.

And that's it! It took a decade for us to get a real solution to this problem, but now you can avoid layout shifts using width and height attributes, or aspect-ratio in CSS, whichever is most appropriate.

View this page on GitHub

Hello, I'm Jake and that's me there. The one that isn't a cat. I'm a developer of sorts.

Feel free to throw me an email , unless you're a recruiter, or someone trying to offer me 'sponsored content' for this site, in which case write your request on a piece of paper, and fling it out the window.

Safari change my image dimensions?

I have a great problem in Safari. Here is the link: http://moghulweb.com/Accomodation/photos.html

its work perfect in chrome , firefox but when i view in safari you will image totally change in height and whole images on that page looks quite bad.

I don’t How to fix that problem. Please help me to solve this issue

Obligatory question - what OS? Windows?

both on windows 7 and 8

Read this thread.

Thanks. I have solve the problem know images are showing well but there is another problem When we click on image then the size of all the images change at once. Why this is only in Safari ?

Because Safari on Windows is known to not work as might be expected and is no longer supported.

If you really want to test Safari best to find another way than on Windows.

Because Safari is very outdated (for Windows) and should never be developed with.

The min-height on the image is confusing safari pc so remove it.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.

NO BUG: Image height issue in safari

Browser : safari OS : macOS URL : beta.bollyworks.com Video : https://www.berrycast.com/conversations/87f7ab73-6be2-5a83-b524-b8693a6a9d05 I have an absolute positioned Logo and it renders fine on chrome. But on safari, the height:100% that comes from the frontend.css stretches to screen height. Could this be a bug?

Not sure if you were asking for a solution or just reporting as a bug, but the solution is to set the height to ‘auto’ on the logo element.

Thanks David. I did try the auto height thing but was thinking this is a bug, given that it does not work on Safari.

Hi Karthik, Thanks so much for your report!

The default image height is needed in some places. The problem with defaults is that there are also cases where they cause problems. In this case, however, the “fix” is more than simple and the problem only occurs in Safari - all other browsers handle the case without problems as far as I can see. Without the default height, we would have problems in all other browsers in significantly more places.

Best regards, timmse

Avatar of Robin Rendle

DigitalOcean provides cloud products for every stage of your journey. Get started with $200 in free credit!

The object-fit property defines how an element responds to the height and width of its content box. It’s intended for images, videos and other embeddable media formats in conjunction with the object-position property. Used by itself, object-fit lets us crop an inline image by giving us fine-grained control over how it squishes and stretches inside its box.

object-fit can be set with one of these five values:

  • fill : this is the default value which stretches the image to fit the content box, regardless of its aspect-ratio.
  • contain : increases or decreases the size of the image to fill the box whilst preserving its aspect-ratio.
  • cover : the image will fill the height and width of its box, once again maintaining its aspect ratio but often cropping the image in the process.
  • none : image will ignore the height and width of the parent and retain its original size.
  • scale-down : the image will compare the difference between none and contain in order to find the smallest concrete object size.

This is how we might set that property:

object-fit example

Because the second image has an aspect ratio that is different than the original image on the left it will stretch outside the realm of its content box, cropping the top and bottom parts of the image.

It’s worth noting that by default the image is centered within its content box but this can be altered with the object-position property.

The demo below shows five examples detailing how we might want an image to squish into a content box which is sometimes smaller or larger than its original width (resize the browser for a better idea of how this might work):

See the Pen object-fit by Robin Rendle ( @robinrendle ) on CodePen .

If the content of the image does not fill the content box for whatever reason then the unfilled space will show the element’s background, in this instance a light grey background.

Related properties

  • object-position

Other resources

  • object-fit on W3C
  • object-fit on MDN
  • object-fit polyfill

Browser support

It’s worth noting that iOS 8-9.3 and Safari 7-9.1 the object-fit property but not object-position .

This browser support data is from Caniuse , which has more detail. A number indicates that browser supports the feature at that version and up.

Mobile / Tablet

The polyfill is a lie! Portal references aside, at the time of writing the polyfill does not currently work in IE which is a real shame for me as I will have to write some JS to continue using this beautiful css prop.

Same here. The whole point of the polyfill is to make IE/Edge be nice. I have poked the IE/Edge dev forum ( https://dev.modern.ie/platform/status// ). We as a community should let MS know what features we really want. It is now ‘Under Consideration’.

There are a few perfectly-working polyfills: * for images: https://github.com/bfred-it/object-fit-images * for videos: https://github.com/jonathantneal/fitie

Just in case someone needs a IE9, IE10, Edge hack solution, I have a workaround, that produces not actually a cropping, but a IMHO acceptable fallback for IE9+: …

… … // IE9 HACK :root figure { height:200px; overflow:hidden; }

Maybe I’m missing something…I don’t see the benefit of this property? Fluid images will fill a parent container and retain their aspect ratio. They can be aligned horizontally with the “text-align” property and vertically with “vertical-align”. The only exception would be if, one wanted the image to be cropped by its parent (object-fit: cover).

The reason I’m looking to use it is exactly what you said. I’m replacing some stuff that used css background images with responsive images, and I need to use object-fit:cover on them. Maybe someone will propose srcset for background images in the css spec instead though. =)

Consider a blog post featured image. If you use background-image as the only way the image is displayed due to design constraints, that image will not display as metadata when the article is shared on Social Media, or in google searches.

You can get the layout benefits of background-image with images without sacrificing the data that you need outside of your side to display your post properly.

Thank you for trick

object fit css not working ie browser.any alternative solution please give soon.

There’s an IE hack three comments up that looks legit. I still haven’t hopped on the “IE’s okay, now!” train, so I don’t know if it really IS legit, but it does seem worth giving a shot.

Great post :) I Love object fit! It made my life easy when styling a website to fit into the design I got. Native LG & Samsung browsers doesn’t support object-fit as well. The polyfill workes great for them.

I’m really digging using object-fit instead of inlining background-images, so I spent an hour or two coming up with a working jQuery polyfill for IE Edge and other non-supporting browsers. Feel free to check it out (and contribute if you see any issues!)

https://github.com/constancecchen/object-fit-polyfill

Alternatively, you can also check out Primož Cigler’s solution, which sets the image as a background-image on the parent container. https://medium.com/@primozcigler/neat-trick-for-css-object-fit-fallback-on-edge-and-other-browsers-afbc53bbb2c3#.sqaa2ssg4

Constance, your polyfill is fantastic. Thank you very much. The others I tried would not work for my situation.

Thank you so much for this (object-fit: contain). Worked like a dream controlling my featured image sizes in cpts.

FYI https://jsfiddle.net/trixta/x2p17f31/ this demo work on ie11 ;)

https://github.com/aFarkas/lazysizes and supports object-position too!

Can we apply object-fit on background images? I’ve been trying for 3 days to scale the bg image down but it shows completely different sections of the image on mobile and laptop

@Abdul I think what you’re looking for will be addressed by the CSS properties background-size ( https://css-tricks.com/almanac/properties/b/background-size/ ) and background-position ( https://css-tricks.com/almanac/properties/b/background-position/ ).

With ‘contain’, how to find out the resulting scaled image size? The image will be constrained in different ways depending on the orientation of both the screen and the image, so it’s not trivial to figure it out; since the browser has already done the work, are there not properties on the img element that are the scaled dimensions?

A reminder on the accessibility implications of choosing between an img element and a CSS background: If the image is purely decorative, then go for a CSS background. Otherwise, an img is more suitable.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Save my name, email, and website in this browser for the next time I comment.

Copy and paste this code: micuno *

Leave this field empty

[solved] Need workaround to make CSS grid work on IOS Safari

According to Can I use... Support tables for HTML5, CSS3, etc , Safari IOS has issues with CSS grid, including when dealing with grid properties such as grid-template-columns (which I am using…).

Known issues: Safari does not yet support intrinsic and extrinsic sizing with grid properties such as grid-template-rows

This is how my styling looks like on IOS safari (you need to use an IOS device to see this. devTools will not show you the bad styling - on devTools it all renders beautifully)

IMG_9144

I have been trying all sorts of things to make this look proper to no results. Has anyone been able to find a workaround for this IOS safari issue in the past? Pointers more than welcome.

The CSS code:

What iPhone are you on? I did a few screenshot tests (using lambdatest) and didn’t see the overflow you have in the picture. Does it overflow in landscape as well?

As far as I can tell, the intrinsic & extrinsic sizing is referring to the use of min-content and max-content . Below is what I’m guessing is the related WebKit bug.

WebKit Bugzilla: Bug 173873 - Support Intrinsic & Extrinsic Sizing with CSS Grid Layout The value min-content is not supported for this grid-template-rows CSS Grid Layout properties such as grid-template-rows do not support min-content, max-content. These properties are needed for certain flexible grid layouts, and are apparently part of the formal syntax.

I’m not so sure if the overflow is grid related. What happens if you remove flex from the container and just use max-width and margin auto. You will have to move the footer out of the container, so it doesn’t get affected.

Unfortunately, I can’t really do much testing.

Edit: Just for reference, here is the CSS Grid implementation meta bug for webkit Bug 60731 - [meta] Implement CSS3 Grid Layout .

Thanks a lot for writing @lasjorg

I’m following up in order:

I’ve tested on Iphone7 and IphoneX (both on latest OS), the overflow happened on both.

I’ve just tried lambdatest and the overflow does not happen there (just like it does not happen when I test in browsers’ devTools on my laptop). The styling breaks only when testing on the actual device (guess lambdatest’s tests might not be very native)

tried your suggestion but with 300px instead as 320px was too large

This is what I get:

IMG_9148

So, kind of better for the “equals” button but the rendering is still lost when sizing the other keys.

:slight_smile:

Ok, first of all, I have to say you’ve got me puzzled! I’ve spent a good hour trying to find a bug in your code, which is a mess btw - you really need to practice in pretty writing.

So, explanation of what’s going on: You trying to control grid cell height with font-size and somehow is scales both width and height on iOS devices ( line-height: 1.5; making things worse). I’ve fixed it assigning fixed height to rows and removing font-size , height and width properties away from grid cells

IMG_5546

For others in the future: a set of things “seemed” to have created the overflow in IOS (once again, this inconsistency only happened on IOS devices when you test natively on the device, do not trust rendering from commercial testing software, they seem to be all using browser’s DevTools - where the overflow does not happen - ).

So, when anyone in the future goes through the same, this is what I’d suggest (bear in mind this is simply a suggestion and the result of tinkering, I cannot find clear cut rationale for the below):

Do not use grid-column property every child element where parent is set to grid-template-columns: repeat(4, 1fr); Stick to defining children that deviates from a standard parent design, i.e. grid-column: 1 / span 4 ;

End result: proper rendering (as per my intended design, with adequately sized fonts) in both Android and IOS devices.

image0

IMAGES

  1. [Solved] 100 viewport height not working in Safari iOS 15

    safari image height auto not working

  2. Does Safari 15 finally fix viewport height? · Luke Channings

    safari image height auto not working

  3. How to Fix Safari Not Loading Images on iPhone

    safari image height auto not working

  4. [BUG] SfImage not setting the image height correctly on Safari · Issue

    safari image height auto not working

  5. javascript

    safari image height auto not working

  6. Fixed: Safari Images Not Loading on iPhone and Mac

    safari image height auto not working

VIDEO

  1. Safari facelift 2023 VS Scorpio N

  2. PICKUP PROBLEM ON DIESEL CAR

  3. Tata Safari Auto Hold Function| Safety in Traffic| Deep Reviews

  4. Android Auto not working

  5. Safari Not Working after iOS 17 Update on iPhone

  6. How To Fix Auto Correct Not Working On Android Phones

COMMENTS

  1. Safari Image Size Auto Height CSS

    For those who needs to use height auto and parent of image is set to display: flex, this trick will help. image { align-self: flex-start; } If your parent of image has set flex-direction: column, you need to do this instead. image { justify-self: flex-start; }

  2. Set image height to 100% and width to auto not working in Safari

    The problem is it being a text image, so I need it to stay in a certain width and only depend on height. If I put 100% width and height auto, it will be really large.... - HannesH. Mar 31, 2014 at 13:08. Then try the image at 50% then it will always be half, I would suggest playing arround with the percentages because with width being auto ...

  3. Safari not computing image aspect ratios from width and height

    I've recently implemented a lazy image loading feature on an image-heavy website, and have been having issues with reflow. I fixed the problem by manually specifying the image dimensions using the `width` and `height` image attributes, as below: It works great in every browser except Safari...

  4. Setting Height And Width On Images Is Important Again

    height (or width) is set in the CSS — including using percentage values like max-width: 100%; width (or height) is set to auto in the CSS. If any one of these were not set, then the calculation would not be possible, and so would fail and be ignored and have to wait for the image to be downloaded.

  5. 100vh problem with iOS Safari

    They are two solutions, the first needs JavaScript and CSS, the second solution required only CSS. 1. JS & CSS solution. Let's get started first with the JS file: appHeight function has sets new style property var (--app-height) including current window height, --app-height it is necessary for next steps. In the previous step I've created the ...

  6. Workaround for aspect-ratio on Safari

    The height will be 384 * 16 / 9 = ~682.66px. However, it doesn't work on most versions of Safari iOS. So my workaround is to calculate it dynamically using JS below: Basically what I do here is to set a ref to the div element I want to apply the aspect-ratio and get the width or height then do the math. I need one of the dimensions to ...

  7. Safari: Height 100% issue

    I thought I explained it quite clearly above. If the parent container is height:auto then a child with height:100% will collapse to height:auto also. If a parent has a usable height (not height ...

  8. How to Fix CSS Issues on Safari

    Displaying properties in Safari. There is a CSS appearance property used to display an element using a platform-native styling based on the users' operating system's theme. To make it work on Safari, we must set the appearance property to its "none" value. Also, use -WebKit- and -Moz- vendor prefixes. Let's see an example, where we use this ...

  9. Avoiding layout shifts: aspect-ratio vs width & height attributes

    The new bit is auto.Here's what the spec says: If both auto and a <ratio> are specified together, the preferred aspect ratio is the specified ratio of width / height unless it is a replaced element with a natural aspect ratio, in which case that aspect ratio is used instead. — CSS-sizing level 4 A lot of articles gloss over this, probably because the spec text is a little hard to read, but ...

  10. Images Stretched In Safari And Chrome

    The height 100% is stretching them. Take that off and you'll be good to go. That height: 100% at the end is causing it. To test just inspect the element in chrome or firefox and click on the img in the html, then uncheck the height: 100% in the right panel and you'll see that it fixes it.

  11. Safari not computing image aspect ratios from width and height ...

    I fixed the problem by manually specifying the image dimensions using the width and height image attributes, as below: It works great in every browser except Safari, but I'm confused because Safari 14 supposedly supports computing aspect ratios based on the width and height attributes . None of my up-to-date macOS or iOS devices seem to ...

  12. Safari change my image dimensions?

    Hi Images in Safari are not scaling as they do in other browsers, rendering an execessive height. I'm also having problems with IE9 and Safari on a media query at 800px where the #footer is ...

  13. NO BUG: Image height issue in safari

    The default image height is needed in some places. The problem with defaults is that there are also cases where they cause problems. In this case, however, the "fix" is more than simple and the problem only occurs in Safari - all other browsers handle the case without problems as far as I can see. Without the default height, we would have ...

  14. Img auto height not working as expected!

    samolex June 9, 2020, 2:21pm 1. I set the img height as auto and the width to 100%. the width worked as expected, but the height didn't as it overflowed the figure container whose height is specified-- the img is contained in the figure tag. On different view-ports the height is changing. Here is what i am saying: This's the figure's ...

  15. Safari not computing image aspect ratios from width and height ...

    It works great in every browser except Safari, but I'm confused because Safari 14 supposedly supports computing aspect ratios based on the width and height attributes. None of my up-to-date macOS or iOS devices seem to recognize this feature in Safari, but they do in every other modern browser.

  16. The Trick To Viewport Units On Mobile

    Now let's get the inner height of the viewport in JavaScript: // First we get the viewport height and we multiple it by 1% to get a value for a vh unit let vh = window. innerHeight * 0.01; // Then we set the value in the --vh custom property to the root of the document. document. documentElement. style.setProperty('--vh', `${vh}px`);

  17. Object-fit

    The object-fit property defines how an element responds to the height and width of its content box. It's intended for images, videos and other embeddable media formats in conjunction with the object-position property. Used by itself, object-fit lets us crop an inline image by giving us fine-grained control over how it squishes and stretches ...

  18. [solved] Need workaround to make CSS grid work on IOS Safari

    Support tables for HTML5, CSS3, etc, Safari IOS has issues with CSS grid, including when dealing with grid properties such as grid-template-columns (which I am using…). Known issues: This is how my styling looks like on IOS safari (you need to use an IOS device to see this. devTools will not show you the bad styling - on devTools it all ...

  19. html

    16. Safari needs the image to have height and width values. Using the image's native width and height i.e. a default value of auto is a change in the new SVG 2 specification. Firefox and Chrome have implemented this and I imagine Safari will too at some point. edited May 11, 2020 at 7:00.