I have a very odd issue... in every browser and mobile version I encountered this behavior:
all the browsers have a top menu when you load the page (showing the address bar for example) which slide up when you start scrolling the page.
100vh sometimes is calculated only on the visible part of a viewport, so when the browser bar slide up 100vh increases (in terms of pixels)
all layout re-paint and re-adjust since the dimensions have changed
a bad jumpy effect for user experience
How can avoid this problem? When I first heard of viewport-height I was excited and I thought I could use it for fixed height blocks instead of using javascript, but now I think the only way to do that is in fact javascript with some resize event...
you can see the problem at: sample site
Can anyone help me with / suggest a CSS solution?
simple test code:
/* maybe i can track the issue whe it occours... */
$(function(){
var resized = -1;
$(window).resize(function(){
$('#currenth').val( $('.vhbox').eq(1).height() );
if (++resized) $('#currenth').css('background:#00c');
})
.resize();
})
*{ margin:0; padding:0; }
/*
this is the box which should keep constant the height...
min-height to allow content to be taller than viewport if too much text
*/
.vhbox{
min-height:100vh;
position:relative;
}
.vhbox .t{
display:table;
position:relative;
width:100%;
height:100vh;
}
.vhbox .c{
height:100%;
display:table-cell;
vertical-align:middle;
text-align:center;
}
<div class="vhbox" style="background-color:#c00">
<div class="t"><div class="c">
this div height should be 100% of viewport and keep this height when scrolling page
<br>
<!-- this input highlight if resize event is fired -->
<input type="text" id="currenth">
</div></div>
</div>
<div class="vhbox" style="background-color:#0c0">
<div class="t"><div class="c">
this div height should be 100% of viewport and keep this height when scrolling page
</div></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Unfortunately this is intentional…
This is a well know issue (at least in safari mobile), which is intentional, as it prevents other problems. Benjamin Poulain replied to a webkit bug:
This is completely intentional. It took quite a bit of work on our part to achieve this effect. :)
The base problem is this: the visible area changes dynamically as you scroll. If we update the CSS viewport height accordingly, we need to update the layout during the scroll. Not only that looks like shit, but doing that at 60 FPS is practically impossible in most pages (60 FPS is the baseline framerate on iOS).
It is hard to show you the “looks like shit” part, but imagine as you scroll, the contents moves and what you want on screen is continuously shifting.
Dynamically updating the height was not working, we had a few choices: drop viewport units on iOS, match the document size like before iOS 8, use the small view size, use the large view size.
From the data we had, using the larger view size was the best compromise. Most website using viewport units were looking great most of the time.
Nicolas Hoizey has researched this quite a bit: https://nicolas-hoizey.com/2015/02/viewport-height-is-taller-than-the-visible-part-of-the-document-in-some-mobile-browsers.html
No fix planned
At this point, there is not much you can do except refrain from using viewport height on mobile devices. Chrome changed to this as well in 2016:
https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/BK0oHURgmJ4
https://developers.google.com/web/updates/2016/12/url-bar-resizing
You can try min-height: -webkit-fill-available; in your css instead of 100vh. It should be solved
in my app I do it like so (typescript and nested postcss, so change the code accordingly):
const appHeight = () => {
const doc = document.documentElement
doc.style.setProperty('--app-height', `${window.innerHeight}px`)
}
window.addEventListener('resize', appHeight)
appHeight()
in your css:
:root {
--app-height: 100%;
}
html,
body {
padding: 0;
margin: 0;
overflow: hidden;
width: 100vw;
height: 100vh;
#media not all and (hover:hover) {
height: var(--app-height);
}
}
it works at least on chrome mobile and ipad. What doesn't work is when you add your app to homescreen on iOS and change the orientation a few times - somehow the zoom levels mess with the innerHeight value, I might post an update if I find a solution to it.
Demo
Look at this answer: https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
// 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`);
// We listen to the resize event
window.addEventListener('resize', () => {
// We execute the same script as before
let vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
});
body {
background-color: #333;
}
.module {
height: 100vh; /* Use vh as a fallback for browsers that do not support Custom Properties */
height: calc(var(--vh, 1vh) * 100);
margin: 0 auto;
max-width: 30%;
}
.module__item {
align-items: center;
display: flex;
height: 20%;
justify-content: center;
}
.module__item:nth-child(odd) {
background-color: #fff;
color: #F73859;
}
.module__item:nth-child(even) {
background-color: #F73859;
color: #F1D08A;
}
<div class="module">
<div class="module__item">20%</div>
<div class="module__item">40%</div>
<div class="module__item">60%</div>
<div class="module__item">80%</div>
<div class="module__item">100%</div>
</div>
For me such trick made a job:
height: calc(100vh - calc(100vh - 100%))
We have new viewport units lvh, svh and dvh to the rescue. This was demonstrated in the latest Google I/O 2022 video on web works.
You would probably want to stick with dvh for the browser to adapt to the mobile device's hidden tabs while scrolling. It works the similar way for width with dvw, lvw and svw units.
Here is a neat illustration from the video: https://youtu.be/Xy9ZXRRgpLk?t=982
Can I use?
This was currently working on my Chrome canary with the flag "Experimental features" enabled.
You can do this by adding following script and style
function appHeight() {
const doc = document.documentElement
doc.style.setProperty('--vh', (window.innerHeight*.01) + 'px');
}
window.addEventListener('resize', appHeight);
appHeight();
Style
.module {
height: 100vh; /* Fallback for browsers that do not support Custom Properties */
height: calc(var(--vh, 1vh) * 100);
}
Set your body position to fixed, set the height to 100%
body { position: fixed; height: 100% }
That's it, then the mobile browser will understand what you want.
Now the body will grow or shrink following the browser's view height, no matter if there is a URL bar or not, or if there are tabs (like in mobile safari) or not. The body will always get full view.
For many of the sites I build the client will ask for a 100vh banner and just as you have found, it results in a bad "jumpy" experience on mobile when you begin to scroll. This is how I solve the problem for a smooth consistent experience across all devices:
I first set my banner element CSS to height:100vh
Then I use jQuery to get the height in pixels of my banner element and apply an inline style using this height.
var viewportHeight = $('.banner').outerHeight();
$('.banner').css({ height: viewportHeight });
Doing this solves the issue on mobile devices as when the page loads, the banner element is set to 100vh using CSS and then jQuery overrides this by putting inline CSS on my banner element which stops it from resizing when a user begins to scroll.
However, on desktop if a user resizes their browser window my banner element won't resize because it now has a fixed height set in pixels due to the above jQuery. To address this I use Mobile Detect to add a 'mobile' class to the body of my document. And then I wrap the above jQuery in an if statement:
if ($('body').hasClass('mobile')) {
var viewportHeight = $('.banner').outerHeight();
$('.banner').css({ height: viewportHeight });
}
As a result, if a user is on a mobile device the class 'mobile' is present on the body of my page and the above jQuery is executed. So my banner element will only get the inline CSS applied on mobile devices meanwhile on desktop the original 100vh CSS rule remains in place.
I came up with a React component – check it out if you use React or browse the source code if you don't, so you can adapt it to your environment.
It sets the fullscreen div's height to window.innerHeight and then updates it on window resizes.
As I was looking for a solution some days, here is mine for everyone using VueJS with Vuetify (my solution uses v-app-bar, v-navigation-drawer and v-footer):
I created App.scss (used in App.vue) with the following content:
.v-application {
height: 100vh;
height: -webkit-fill-available;
}
.v-application--wrap {
min-height: 100vh !important;
min-height: -webkit-fill-available !important;
}
You can try giving position: fixed; top: 0; bottom: 0; properties to your container.
#nils explained it clearly.
What's next then?
I just went back to use relative 'classic' % (percentage) in CSS.
It's often more effort to implement something than it would be using vh, but at least, you have a pretty stable solution which works across different devices and browsers without strange UI glitches.
The the problem still remains to this date, unfortunately. And the biggest misleading it's impossible to represent the situation by using browser's devices toolbar.
I've just solved the issue like so (tested on PC, iOS and android browsers):
.your_class {
height: 100vh,
max-height: 100%, // <-- add the line
...some other props,
}
I hope it'll save your time.
The following code solved the problem (with jQuery).
var vhHeight = $("body").height();
var chromeNavbarHeight = vhHeight - window.innerHeight;
$('body').css({ height: window.innerHeight, marginTop: chromeNavbarHeight });
And the other elements use % as a unit to replace vh.
As I am new, I can't comment on other answers.
If someone is looking for an answer to make this work (and can use javascript - as it seems to be required to make this work at the moment) this approach has worked pretty well for me and it accounts for mobile orientation change as well. I use Jquery for the example code but should be doable with vanillaJS.
-First, I use a script to detect if the device is touch or hover. Bare-bones example:
if ("ontouchstart" in document.documentElement) {
document.body.classList.add('touch-device');
} else {
document.body.classList.add('hover-device');
}
This adds class to the body element according to the device type (hover or touch) that can be used later for the height script.
-Next use this code to set height of the device on load and on orientation change:
if (jQuery('body').hasClass("touch-device")) {
//Loading height on touch-device
function calcFullHeight() {
jQuery('.hero-section').css("height", $(window).height());
}
(function($) {
calcFullHeight();
jQuery(window).on('orientationchange', function() {
// 500ms timeout for getting the correct height after orientation change
setTimeout(function() {
calcFullHeight();
}, 500);
});
})(jQuery);
} else {
jQuery('.hero-section').css("height", "100vh");
}
-Timeout is set so that the device would calculate the new height correctly on orientation change. If there is no timeout, in my experience the height will not be correct. 500ms might be an overdo but has worked for me.
-100vh on hover-devices is a fallback if the browser overrides the CSS 100vh.
I just found a web app i designed has this issue with iPhones and iPads, and found an article suggesting to solve it using media queries targeted at specific Apple devices.
I don't know whether I can share the code from that article here, but the address is this: http://webdesignerwall.com/tutorials/css-fix-for-ios-vh-unit-bug
Quoting the article: "just match the element height with the device height using media queries that targets the older versions of iPhone and iPad resolution."
They added just 6 media queries to adapt full height elements, and it should work as it is fully CSS implemented.
Edit pending: I'm unable to test it right now, but I will come back and report my results.
Do not use recommended approaches such as -webkit-fill-available.
I just spent all day rushing around to fix this "bug".
Add a class when your app is loaded with a browser with a "chin".
JavaScript
// Angular example but applicable for any JS solution
#HostBinding('class.browser-has-chin') browserHasChin: boolean = false;
public ngOnInit(): void {
this.browserHasChin = this._isMobileSafari();
}
private _isMobileSafari() {
return navigator.userAgent.match(/(iPod|iPhone|iPad)/) && navigator.userAgent.match(/AppleWebKit/) ? true : false;
}
CSS
.browser-has-chin {
#media screen and (max-device-width: 767px){
// offset with padding or something
}
}
NOTES:
There are major issues with the -webkit-fill-available prop for cross-browser compatibility.
I was able to get it working in Chrome and iOS Safari to fix the chin/height calculation issue. However it broke Android Chrome and Firefox had bugs with it too.
It seems that -webkit-fill-available was rushed into webkit at some point and perhaps adopted haphazardly by Apple as a fix for chin/height calculation?
It relies on intrinsic sizing which is NOT safe to use yet.
I have created two examples below:
To showcase how height: 100vh as height can lead to scroll in mobile chrome browsers:
code : https://codesandbox.io/embed/mobile-viewport-100vh-issue-nxx8z?fontsize=14&hidenavigation=1&theme=dark
demo: https://nxx8z.csb.app/
Solution using position: fixed to resolve the issue and with purely CSS:
code : https://codesandbox.io/s/mobile-viewport-100vh-issue-fix-forked-ypx5x?file=/index.html
demo : https://ypx5x.csb.app/
The VH 100 does not work well on mobile as it does not factor in the iOS bar (or similar functionality on other platforms).
One solution that works well is to use JavaScript "window.innerHeight".
Simply assign the height of the element to this value e.g.
$('.element-name').height(window.innerHeight);
Note: It may be useful to create a function in JS, so that the height can change when the screen is resized. However, I would suggest only calling the function when the width of the screen is changed, this way the element will not jump in height when the iOS bar disappears when the user scrolls down the page.
React hooks solution with useEffect and useState
function App() {
const [vh, setVh] = useState(window.innerHeight);
useEffect(() => {
const updateVh = () => {
setVh(window.innerHeight);
};
window.addEventListener('resize', updateVh);
return () => window.removeEventListener('resize', updateVh);
}, []);
return (
<div style={{ height: vh }}>
{vh} px
</div>
);
}
Demo: https://jsfiddle.net/poooow/k570nfd9/
Because it won't be fixed, you can do something like:
# html
<body>
<div class="content">
<!-- Your stuff here -->
</div>
</body>
# css
.content {
height: 80vh;
}
For me it was the fastest and more pure solution than playing with the JavaScript which could not work on many devices and browsers.
Just use proper value of vh which fits your needs.
The following worked for me:
html { height: 100vh; }
body {
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100vw;
}
/* this is the container you want to take the visible viewport */
/* make sure this is top-level in body */
#your-app-container {
height: 100%;
}
The body will take the visible viewport height and #your-app-container with height: 100% will make that container take the visible viewport height.
Using vh on mobile devices is not going to work with 100vh, due to their design choices using the entire height of the device not including any address bars etc.
If you are looking for a layout including div heights proportionate to the true view height I use the following pure css solution:
:root {
--devHeight: 86vh; //*This value changes
}
.div{
height: calc(var(--devHeight)*0.10); //change multiplier to suit required height
}
You have two options for setting the viewport height, manually set the --devHeight to a height that works (but you will need to enter this value for each type of device you are coding for)
or
Use javascript to get the window height and then update --devheight on loading and refreshing the viewport (however this does require using javascript and is not a pure css solution)
Once you obtain your correct view height you can create multiple divs at an exact percentage of total viewport height by simply changing the multiplier in each div you assign the height to.
0.10 = 10% of view height
0.57 = 57% of view height
Hope this might help someone ;)
Here's a work around I used for my React app.
iPhone 11 Pro & iPhone Pro Max - 120px
iPhone 8 - 80px
max-height: calc(100vh - 120px);
It's a compromise but relatively simple fix
A nice read about the problem and its possible solutions can be found in this blog post: Addressing the iOS Address Bar in 100vh Layouts
The solution I ended up in my React application is utilising the react-div-100vh library described in the post above.
Brave browser on iOS behaves differently (buggy?). It changes viewport height dynamically accordingly to showing/hiding address bar. It is kind of annoying because it changes page's layout dependent on vw/vh units.
Chrome and Safari is fine.
I solved it by putting the most outer div at position: absolute and then just setting the height to 100%:
CSS:
.outer {
position: absolute;
height: 100%;
}
HTML:
<div class="outer">
<!-- content -->
</div>
It seems like CSS fix is unreliable and JS one works fine but the element is jumping when user opens the page.
I solved the issue using JS from other answers + fadeIn animation to hide jumping.
This won't fit all the use cases, but for some of them, like a button that has to be at the bottom, could be a good solution.
The people who found this answer and are struggling with an issue of wiered jumping of elements on mobile view when scrolling downward/upward whose position is fixed w.r.t the root element need to specify the property in terms of bottom rather than top and should give a field value in px. This solves the issue
change this:
element{
position: fixed;
top: 90vh;
left: 90vh;
transform: translate(-95%, -95%);
}
to this:
element{
position: fixed;
bottom: 90px; /* this is the change */
left: 90vh;
transform: translate(-95%, -95%);
}
I have a webpage that consists of three panels: header, main and footer. In my .css file, I have successfully adjusted my webpage to fill 100% of the screen's vertical height using "100vh".
.EventHeader {
height: 60px;
}
.EventMain {
height: calc(100vh - 140px);
text-align: left;
overflow-y: auto;
}
.EventFooter {
height: 80px;
}
While this works great with most mobile devices, I'm finding that in iOS Safari their address bar and tabs play havoc to the actual display. If the address bar and tabs are visible, the webpage fills more than 100% of the screen. However, once these two items disappear the webpage takes up 100% of the vertical height as desired.
For example, if vertical height is 720px, then in all mobile devices except iOS Safari, these are the heights of the panels (i.e. in aggregate takes up exactly 100% of the vertical height but not more than 100%):
EventHeader: 60px
EventMain: 580px which is 720 - 60 - 80
EventFooter: 80px
"vh" property reads 720px
When the page origianlly renders in iOS Safari and the address bar and tabs are visible (which take up roughly 44px), these are the heights of the panels (i.e. in aggregate takes up 764px which is 44px more than 100% of the vertical height):
EventHeader: 60px
EventMain: 624px which is 720px - 60px - 80px + 44px
EventFooter: 80px
"vh" property reads 764px
But once the address bar and tabs have disappeared (roughly 15 seconds later), these are the heights of the panels (i.e. in aggregate takes up exactly 100% of the vertical height but not more than 100%):
EventHeader: 60px
EventMain: 580px which is 720 - 60 - 80
EventFooter: 80px
"vh" property reads 720px
So while the actual vertical height of the window is always 720px, the vertical height is somehow modified based of the visibility of the address bar and tabs in iOS Safari.
Unless I'm completely mistaken, this cannot be fixed using flexbox or other similar approaches. Rather, it is a specific issue with iOS where the height.inner property of the window changes based on the visibility of the address bar and tabs. And, this attribute is what is recorded in the "vh" property in css.
I have searched around and found that the best solution is in the following article:
https://github.com/alvarotrigo/fullPage.js/issues/2414
var height = window.innerHeight;
var a = setInterval(function() {
$(window).scrollTop(-1);
resize();
}, 500); // Don't lower more than 500ms, otherwise there will be animation-problems with the Safari toolbar
$(window).on('resize', function() {
resize();
});
var resize = function() {
if(window.innerHeight != height) {
height = window.innerHeight;
$('.section').css('height', height + 'px');
}
};
However, it is in jQuery and I am having problems converting it to pure JS and using it in a React program.
I understand the basic process:
set the css "height" parameter to "innerHeight"
after a defined period of time, assume that the address bar and tabs have disappeared
treat this disappearance as a window resizing
on a window resizing, reassign the "height" parameter to "innerHeight"
Also, how would I send this "height" parameter and its assigned value back to my .css file?
Do I instead need to use inline styling?
Any help would be appreciated. Thanks.
I'm using Joomla 3.3.4 FYI.
I have an image on the front page (http://www.ckdev.info/cdp) that's a call to action to complete a form for a free estimate. It's great in desktop or tablet (landscape) as the form appears to the right.
However, when viewed on other devices or orientations, the viewport is too small to have the sidebar showing on the right and it drops to the bottom. So the "right arrow" image doesn't make logical sense.
What I want to do is a bit of an "if-else" solution. If screen width is xx px or greater show "right-arrow.jpg", else "down-arrow.jpg". I will attach a anchor to the form so that clicking/touching down-arrow.jpg when displayed will scroll down to the form.
I'm afraid I'm no coder so, while I have no doubt this can be done, I have no clue how! Thanks.
You can do it with css media-queries.
Try this: (change 900px and 899px to your desired values)
#media(min-width: 900px) {
#img {
width: 100%;
height: 150px;
background: url('http://www.ckdev.info/cdp/images/estimate.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
}
#media(max-width: 899px) {
#img {
width: 100%;
height: 100px;
background: url('http://www.ckdev.info/cdp/images/estimate.png');/*change image url*/
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
}
Check it out here: jsFiddle (resize result window width to more than 900px)
I've just made your image different size on different media queries, but instead change your background url to your desired image.
You can make this happen using jQuery without anything extra as long as you don't mind some odities in the width of the window that come from the scrollbar. Ill get back to the scrollbar in a sec. To test the width you can use jQuery(window).width(). This will return the width of the window in pixels. Exactly what you are looking for. An example snippet:
jQuery(document).ready(function(){
if (jQuery(window).width() > 1000){
jQuery(<select img here>).attr('src', '/path/to/new/image.jpg');
}
});
I notice that you dont have a class or id on the image you mentioned. I would suggest adding an id to make it easier to select. For example, <img src="/cdp/images/estimate.png" alt="Get a free interior or exterior painting estimate" id="estimate-with-arrow">. If you make this change you can swap out <select img here> for 'img#estimate-with-arrow' (this will select an the image with id estimate-with-arrow). And voila, image swap.
I will note three things.
First, that this will only work on initial page load. If a user loads the page at full desktop width then shrinks it down, the image will not change when it passes the break point. You need to bind to the resize to get this to work:
jQuery(window).resize(function() {
<code here>
});
Second, I set up this particular code to swap out the image for any screen over 1000 px. This means you will only ever load one image for smaller devices, saving bandwidth. This is preferred, ad mobile plans are more finicky.
And third, the scrollbar. Testing the window width using jQuery will not match the same break point as css. I use modernizr to get around this. This is a bit more advanced though.
What you want is a CSS media query to change the displayed image.
For a smartphone like the iphone in portait it would be something like that:
#media only screen and (min-device-width : 320px) and (max-device-width : 568px) and (orientation : portrait)
{ /* STYLES GO HERE */}
For more details take a look at:
w3schools
cssmediaqueries
I'm building up a website using fullpage.js. When zoomed 100%, the webpage looks great, yet, when zooming just 25% more, texts and imgs will start overlapping or even disappearing, as each section has very limited height (with no scrolling), making my webpage impossible to read. I'm using
em
unit for font sizes and percentages for sizes, imgs and margins (except if its too little margin (5px, for example), where I use
px
). Hence, I was wondering if there's a solution using Javascript, CSS or HTML which can maintain font size even if the webpage is zoomed. As of now, I've tried, with no success, the following:
document.body.style.zoom="100%"
-webkit-text-size-adjust: none;
Using fullpage's feature resize, but it only works if the user resizes the window once the page has loaded.
document.body.style.webkitTransform = 'scale(1)'
My website is (sorry, I don't know which part of it to post, as the issue involves all of it):
http://rienpipe.es
Thanks in advanced!
you can fix this by using #media query's and a viewport in your css , and add this meta tag to your html:
<meta name="viewport" content="width=device-width,initial-scale = 1.0,maximum-scale = 1.0”>
and with the #media query's and viewport you declare what size you have per screen width using this media query + viewport in css:
#media screen and (min-width: 820px) and (max-width: 920px) {
#viewport { width: 820px; }
// your css for screens between 820 and 920 pixels in width goes here
}
i mostly use the value's : from 20 - 600 , 600-700 , 700-820 , 820 - 920 , 920 - 1200, #media screen and (min-width: 1200px){ #viewport { width: 1200px; }(this last one will set the size for any screen bigger than 1200 px in width so your code for the biggest version goeds here}
So this means you will have 6 times your css code which is adapted will be adapted to the size.
This is called adaptive or responsive design and is pretty easy to do
For more info you might check this http://css-tricks.com/snippets/css/media-queries-for-standard-devices/
In my CSS I have code like this:
html {
background:blue;
}
#media screen and (max-width: 980px)
html {
background:red;
}
So when the browser window is less than 980px, background turns red, the rest of the time, it is blue.
I resized my window to 970px (according to CSS) and the background is red. But when I use jquery to do a alert($(window).width()), which gave me a pop up saying 1000px
Why would $(window).width() reporting a larger value than what CSS expects?
I believe there's a difference between the visible page and the window size. In vanilla JS, so far as I understand:
window.innerWidth, window.innerHeight
(the page's visible width/height)
window.outerWidth, window.outerHeight
(the browser outer width/height)
It strikes me that this is probably why - the value being returned is the outer width of the browser window. Source
There is not enough of background to tell you what exactly happens in your browser.
I wrote the following page to test everything out:
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<style>
html { background:blue; }
#media screen and (max-width: 980px) {
html { background:red; }
}
</style>
</head>
<body>test</body>
</html>
And after testing it with the inspector, $(window).width() inside of the Chromium inspector shows exactly what it should be.
While screen is red, following style is set in inspector:
margin-left: 8px;
margin-right: 8px;
width: 964px;
...and jquery in console shows:
> $(window).width()
980
Total width is the width + all the margins. So, it is: 964 + 8 + 8 = 980.
In my opinion, this inconsistency is caused by margins and possibly borders set for tags you are measuring and any parent tags. I don't see any other reasons of this behaviour.
I hope this helps.
I figured out the problem.
In chrome, i pressed CTRL MINUS a few times so the window scaled in a way to have smaller text. Once this is done, jquery wil report a different window width from what css report