I'm still wet behind the ears with web dev, not the best at math, and have problems moving on when something is still broken. Hopefully you guys can help.
Quick: I'm using Jquery to make some (dynamic in number) divs in my header overlap by 30%, filling the entire width of the container. My current iteration rounds up one too many times, so my last element goes beneath the rest.
I have X elements filling the full width of my header container. Each element overlaps by 30% on either side. In an equation, I can work out the math no problem. Ensuring pixel precision with these numbers has proven more difficult. This is what I'm using to determine the width of each element.
width of element = [container width] / ((.7 * ([# of elements] - 1)) + 1)
left margin of element = [width of element] * .3
I make variables I call extraWidth and extraMargin which are the width and margin % 1 respectively. The default element width I use now is width-(width%1). For every element, I add the extraWidth and extraMargin to running total variables. Any time the total of either of these variables exceeds .5, that particular element has its width or margin set 1 higher than the default.
So I don't run on any longer, here's a JSFiddle with everything necessary to see what I'm dealing with. It runs fine most of the time, but at certain widths I'm 1 pixel too wide.
p.s.
Ran the JSFiddle, didn't work the same way as my live sandbox site, so check that out here. I feel like I included all the necessary bits, but I can't say for sure. On my Chrome, when window size is 575px (among many other widths) it's messed up.
EDIT
It should be noted that I'm making changes to my live site without updating this post. I'm not deleting any functions just yet though, just making new ones/minor alterations to existing ones.
Recursion! Recursion was the most elegant answer (which appears to work in ALL cases) I could come up with.
Iterating through my jQuery object one element at a time and calculating the width and margin based on the remaining container width rather than the whole container width makes this much easier to calculate.
function circleWidth(circles, containerWidth) {
var width = containerWidth / ((.7 * (circles.length - 1)) + 1);
var pxWidth = Math.round(width);
var margin = width * .3;
var pxMargin = Math.round(margin);
$(circles[0]).css({
'width': pxWidth + "px",
'margin-left': "-" + pxMargin + "px"
});
containerWidth -= (pxWidth - pxMargin);
if (circles.length > 1) {
circleWidth(circles.slice(1), containerWidth);
}
}
function circleSize(circles, containerWidth) {
var height = Math.ceil(containerWidth / ((.7 * (circles.length - 1)) + 1));
circles.each(function() {
$(this).css({
'height': height + "px"
});
});
circleWidth(circles, containerWidth);
$(circles[circles.length]).css({
'margin-left': $(circles[0]).css('margin-left')
});
$(circles[0]).css({
'margin-left': 0
});
}
Here's the fiddle with my final result. I'm sure I still have some optimization to do, but at least it's working now.
You have 2 choices:
Calculate pixelMargin as next integer. like:
var pixelMargin = Math.ceil(circleMargin);
or you can use pixelMargin in %.
1st one worked for me.
I'm updating a table header and its first column positions programatically based on how the user scrolls around to keep them aligned.
The issue I'm experiencing is that as soon as my data sets gets big enough, the scrolling gets more and more choppy/less smooth.
The relevant code is at the very bottom of the fiddle:
iScroll.on('scroll', function(){
var pos = $('#scroller').position();
$('#pos').text('pos.left=' + pos.left + ' pos.top=' + pos.top);
// code to hold first row and first column
$('#scroller th:nth-child(1)').css({top: (-pos.top), left: (-pos.left), position:'relative'});
$('#scroller th:nth-child(n+1)').css({top: (-pos.top), position:'relative'});
// this seems to be the most expensive operation:
$('#scroller td:nth-child(1)').css({left: (-pos.left), position:'relative'});
});
I know that this can be written a lot more efficent by caching the elements and so on. For example, I have tried saving the elements in to an array and updating their position in a more "vanilla" fashion:
headerElements[i].style.left = left + 'px'; // etc...
No matter how fast I make the callback, I'm still not happy about the result. Do you have any suggestions?
https://jsfiddle.net/0qv1kjac/16/
Just use ClusterizeJS! It can handle hundreds of thousands of rows and was built exactly for this purpose.
How does it work, you ask?
The main idea is not to pollute DOM with all used tags. Instead of that - it splits the list to clusters, then shows elements for current scroll position and adds extra rows to top and bottom of the list to emulate full height of table so that browser shows scrollbar as for full list
To be able to handle big amounts of data you need data virtualization. It has some restrictions, though.
First you need to decide the size of a view port. Let's say you want to render 10 items in a row and 20 items in column. It would be 10x20 items then. In you fiddle it's div with id wrapper.
Then you need to know total amount of data you have. From your fiddle it would be 100x100 items. And, also you need to know height and width of a item (cell). Let's take 40x120 (in px).
So div#wrapper is a view port, it should have fixed sized like 10x20 items. Then you need to set up correct width and height for table. The height of table would be equal to total amount of data in column including head by item height. Width for table would be total amount of items in single row by item width.
Once you set up these, div#wrapper will receive horizontal and vertical scrolls. Now you able to scroll left and bottom, but it will be just empty space. However this empty space is able to hold exact amount of data you have.
Then you need to take scroll data left and top (position), which comes in pixels and normalize it to amount of items, so you could know not how many pixels you've scrolled, but how many items you've scrolled(or rows if we scroll from top to bottom).
It could be done by division of pixels scrolled on item height. For example, you scrolled to left by 80px, that's 2 items. It means these items should be invisible because you've scrolled past them. So you know that you scrolled past 2 items, and you know that you should see 10 items in a row. That means you take your data array which has data for row with 100 items, and slice it like this:
var visibleItems = rowData.slice(itemsScrolled, itemsScrolled + 10);
It will give you items which should be visible in viewport at current scroll position. Once you have these items you need to construct html and append it to table.
Also on each scroll event you need to set top and left position for tbody and thead so they would move with scroll, otherwise you will have your data, but it will be at (0; 0) inside a viewport.
Anyway, code speaks thousand of words, so here's the fiddle: https://jsfiddle.net/Ldfjrg81/9/
Note, that this approach requires heights and widths to be precise, otherwise it will work incorrectly. Also if you have items of different sizes, this also should be taken into consideration, so better if you have fixed and equal sizes of items. In jsfiddle, I commented out the code which forces first column to stay in place, but you can render it separately.
It's a good solution to stick to some library as suggested in comments, since it handles a lot of cases for you.
You can make rendering even faster if use react.js or vue.js
This won't be the answer your are looking for but here's my 2 cents anyway.
Javascript animation (especially given the amount that the DOM has to render) will never be as smooth as you want it. Even if you could get it smooth on your machine, chances are that it will vary drastically on other peoples (Older PC's, Browsers etc).
I would see 2 options if I were to tackle this myself.
Go old school and add a horizontal and vertical scrollbar. I know it's not a pretty solution but it would work well.
Only render a certain amount of rows and discard those off screen. This could be a bit complicated but in essence you would render say 10 rows. Once the user scrolls to a point where the 11th should be there, render that one and remove the 1st. You would pop them in and out as needed.
In terms of the actual JS (you mentioned putting elements in to an array), that isn't going to help. The actual choppyness is due to the browser needing to render that many elements in the first place.
You're experiencing choppy / non-smooth scrolling because the scroll event fires at a very high pace.
And every time it fires you're adjusting the position of many elements: this is expensive and furthermore until the browser has completed the repaint it's unresponsive (here the choppy scrolling).
I see two options:
Option number one: display only the visible subset of the whole data set (this has been already suggested in another answer so I won't go futher)
Option number two (easier)
First, let animations on left and top css changes occurr via transitions. This is more efficient, is non-blocking and often let the browser take advantage of the gpu
Then instead of repeteadly adjust left and top, do it once a while; for example 0.5 seconds. This is done by the function ScrollWorker() (see code below) that recalls itself via a setTimeout().
Finally use the callback invoked by the scroll event to keep the #scroller position (stored in a variable) updated.
// Position of the `#scroller` element
// (I used two globals that may pollute the global namespace
// that piece of code is just for explanation purpose)
var oldPosition,
newPosition;
// Use transition to perform animations
// You may set this in the stylesheet
$('th').css( { 'transition': 'left 0.5s, top 0.5s' } );
$('td').css( { 'transition': 'left 0.5s, top 0.5s' } );
// Save the initial position
newPosition = $('#scroller').position();
oldPosition = $('#scroller').position();
// Upon scroll just set the position value
iScroll.on('scroll', function() {
newPosition = $('#scroller').position();
} );
// Start the scroll worker
ScrollWorker();
function ScrollWorker() {
// Adjust the layout if position changed (your original code)
if( newPosition.left != oldPosition.left || newPosition.top != oldPosition.top ) {
$('#scroller th:nth-child(1)').css({top: (-newPosition.top), left: (-newPosition.left), position:'relative'});
$('#scroller th:nth-child(n+1)').css({top: (-newPosition.top), position:'relative'});
$('#scroller td:nth-child(1)').css({left: (-newPosition.left), position:'relative'});
// Update the stored position
oldPosition.left = newPosition.left;
oldPosition.top = newPosition.top;
// Let animation complete then check again
// You may adjust the timer value
// The timer value must be higher or equal the transition time
setTimeout( ScrollWorker, 500 );
} else {
// No changes
// Check again after just 0.1secs
setTimeout( ScrollWorker, 100 );
}
}
Here is the Fiddle
I set the Worker pace and the transition time to 0.5 secs. You may adjust the value with higher or lower timing, eventually in a dinamic way based on the number of elements in the table.
Yes! Here are some improvements to the code from your JS Fiddle. You can view my edits at: https://jsfiddle.net/briankueck/u63maywa/
Some suggested improvements are:
Switching position:relative values in the JS layer to position:fixed in the CSS layer.
Shortening the jQuery DOM chains, so that the code doesn't start at the root element & walk all the way through the dom with each $ lookup. The scroller is now the root element. Everything uses .find() off of that element, which creates shorter trees & jQuery can traverse those branches faster.
Moving the logging code out of the DOM & into the console.log. I've added a debugging switch to disable it, as you're looking for the fastest scrolling on the table. If it runs fast enough for you, then you can always re-enable it to see it in the JSFiddle. If you really need to see that on the iPhone, then it can be added into the DOM. Although, it's probably not necessary to see the left & top position values in the iPhone.
Remove all extraneous $ values, which aren't mapped to the jQuery object. Something like $scroller gets confusing with $, as the latter is the jQuery library, but the former isn't.
Switching to ES6 syntax, by using let instead of var will make your code look more modern.
There is a new left calculation in the <th> tag, which you'll want to look at.
The iScroll event listener has been cleaned up. With position:fixed, the top <th> tags only need to have the top property applied to them. The left <td> tags only need to have the left property applied to them. The corner <th> needs to have both the top & left property applied to it.
Remove everything that's unnecessary, like the extraneous HTML tags which were used for logging purposes.
If you really want to go more vanilla, change out the .css() methods for the actual .style.left= -pos.left + 'px'; and .style.top= -pos.top + 'px'; properties in the JS code.
Try using a diff tool like WinMerge or Beyond Compare to compare the code from your version to what's in my edits, so that you can easily see the differences.
Hopefully, this will make the scrolling smoother, as the scroll event doesn't have to process anything that it doesn't need to do... like 5 full DOM traversing look-ups, rather than 3 short-tree searches.
Enjoy! :)
HTML:
<body>
<div id="wrapper">
<table id="scroller">
<thead>
</thead>
<tbody>
</tbody>
</table>
</div>
</body>
CSS:
/* ... only the relevant bits ... */
thead th {
background-color: #99a;
min-width: 120px;
height: 32px;
border: 1px solid #222;
position: fixed; /* New */
z-index: 9;
}
thead th:nth-child(1) {/*first cell in the header*/
border-left: 1px solid #222; /* New: Border fix */
border-right: 2px solid #222; /* New: Border fix */
position: fixed; /* New */
display: block; /*seperates the first cell in the header from the header*/
background-color: #88b;
z-index: 10;
}
JS:
// main code
let debug = false;
$(function(){
let scroller = $('#scroller');
let top = $('<tr/>');
for (var i = 0; i < 100; i++) {
let left = (i === 0) ? 0 : 1;
top.append('<th style="left:' + ((123*i)+left) + 'px;">'+ Math.random().toString(36).substring(7) +'</th>');
}
scroller.find('thead').append(top);
for (let i = 0; i < 100; i++) {
let row = $('<tr/>');
for (let j = 0; j < 100; j++) {
row.append('<td>'+ Math.random().toString(36).substring(7) +'</td>');
}
scroller.find('tbody').append(row);
}
if (debug) console.log('initialize iscroll');
let iScroll = null;
try {
iScroll = new IScroll('#wrapper', {
interactiveScrollbars: true,
scrollbars: true,
scrollX: true,
probeType: 3,
useTransition:false,
bounce:false
});
} catch(e) {
if (debug) console.error(e.name + ":" + e.message + "\n" + e.stack);
}
if (debug) console.log('initialized');
iScroll.on('scroll', function(){
let pos = scroller.position();
if (debug) console.log('pos.left=' + pos.left + ' pos.top=' + pos.top);
// code to hold first row and first column
scroller.find('th').css({top:-pos.top}); // Top Row
scroller.find('th:nth-child(1)').css({left:-pos.left}); // Corner
scroller.find('td:nth-child(1)').css({left:-pos.left}); // 1st Left Column
});
});
Is it necessary that you create your own scroller? Why don't you just style the data in HTML/CSS and just use the overflow attribute? JavaScript needs work on it's ability to adjust framerates. I was using your jFiddle earlier and it worked just fine with the native overflow handler.
Found this in the manual. Probably not what you wanna hear but it's the way it is:
IScroll is a class that needs to be initiated for each scrolling area. There's no limit to the number of iScrolls you can have in each page if not that imposed by the device CPU/Memory.
Try to keep the DOM as simple as possible. iScroll uses the hardware compositing layer but there's a limit to the elements the hardware can handle.
The reason the performance degradation is happening is that your scroll event handler is firing again and again and again instead of waiting for a reasonable and imperceptible interval.
The screenshot shows what happened when I tracked how many times the event handler fired, while scrolling for just a few seconds. The computationally-heavy event handler was fired over 600 times!!! This is more than 60 times per second!!!
It may seem counter-intuitive, but reducing the frequency that the table is updated will vastly increase perceived response times. If your user scrolls for fraction of a second, about 150 milliseconds, and the table is updated ten times, freezing the display during the scrolling, the net result is far worse than if the table were updated only three times and moved fluidly rather than freezing. It is just wasted processor burn to update more times than the browser can handle without freezing.
So, how do you make an event handler that fires at a maximum frequency, for example 25 times per second, even it is triggered much more often, like 100 times per second?
The naive way of doing it is to run a setInterval event. That is better, but horribly inefficient as well. There is a better way of doing it, by setting a delayed event handler, and clearing it on subsequent invocations before setting it again, until the minimum time interval has passed. This way it only runs no more often than at the maximum desired frequency. This is one major case for why the ``clearInterval'' method was invented.
Here is live working code:
https://jsfiddle.net/pgjvf7pb/7/
Note: when refreshing continuously like this, the header column may appear out of position.
I advise to do the update only when the scrolling has paused for about 25ms or so, rather than continuously. This way, it appears to the user that the header column is dynamically calculated as well as being fixed in place, because it appears instantly after scrolling rather than seeming to scroll with the data.
https://jsfiddle.net/5vcqv7nq/2/
The logic is like this:
variables outside your event handler
// stores the scrolling operation for a tiny delay to prevent redundancy
var fresh;
// stores time of last scrolling refresh
var lastfresh = new Date();
operations inside your event handler
// clears redundant scrolling operations before they are applied
if (fresh) clearTimeout(fresh);
var x = function() {
// stores new time of scrolling refresh
lastfresh = new Date();
// perform scrolling update operations here...
};
// refresh instantly if it is more than 50ms out of date
if (new Date() - lastfresh > 50) x();
// otherwise, pause for half of that time to avoid wasted runs
else fresh = setTimeout(x, 25);
Demo: https://jsfiddle.net/pgjvf7pb/7/
Once again, I recommend that you remove the line of code that refreshes the data instantly, and the else condition after that, and simply use one line
fresh = setTimeout(x, 25);
This will appear to instantly calculate the header column the moment any scrolling is finished, and saves even more operations. My second link to JS Fiddle shows what this looks like, here: https://jsfiddle.net/5vcqv7nq/2/
I have created this jsFiddle:
https://jsfiddle.net/j994tnu2/4/
if(textH < (parentH - deviation) || textH > (parentH + deviation)) {
text.style.transform = "scale(1, " + frameScale + ')';
//alert("transform");
}
https://jsfiddle.net/j994tnu2/5/
if(textH < (parentH - deviation) || textH > (parentH + deviation)) {
//text.style.transform = "scale(1, " + frameScale + ')';
//alert("transform");
}
Version 4 has 1 line uncommented which allows for a tranform: scale() of the div directly containing the text.
Version 5 has this 1 line commented which disallows this to happen.
My concern is that the way I've coded the text to resize is...
textScale1 = 0.78;
textScale2 = 1;
textScale3 = 1.4;
//textScale4 = fontSize2 / fontSize;
//applies the master frameScale once to a single style of a class
fontSize2 = Math.round(10 * fontSize2 * frameScale) / 10;
//uses the relative textScales to this element to style the rest
fontSize = Math.round(10 * fontSize2 / textScale1) / 10;
lineH = fontSize;
margin = Math.round(10 * fontSize2 / textScale2) / 10;
lineH2 = fontSize2;
margin2 = Math.round(10 * fontSize2 / textScale3) / 10;
by manually checking the font-size and margins of every element and changing them to a scale both relative to themselves in the text AND relative to the outer div container size. This is actually the good part which makes the text stay true to itself relative to the original format. However,
The problem I have is the difference between the onload = function and the addEventListener(resize, function). They are coded exactly the same but have "different" results.
If you resize the window you'll see that after about 3 resizes, the text fits the container on an absolute font-size level much more closely and has much less (or none at all) transform: scale() stretching or squashing.
But every time the onload = function gets called, the text will always be way too big or small for the container and will always get stretched or squashed by an unacceptable amount.
How can I code this up to make the font-sizes in the onload = function be true to the starting outer div height?
Thanks for looking into it.
EDIT: It's interesting. Commenting out the onload=function and letting the resize function do the first resize, you will get the exact same result of the onload=function. Which, consistency is good. But why does subsequent resizing increase the accuracy of the font-sizes? Even if I resize up and then back down to near the same spot the text will look less squished and more true to its proportions. The initial resize sucks. Why? How is it possible that it gains in accuracy over time?
So I've kept working at it and saw that the ratio of the outer text div to the inner text div (frameScale in the jsFiddle) would determine the percent deviation at the end. This is what I mean:
However far from 1.0, that frameScale would deviate would determine according to some odd exponential function how far the resultant frameScale was from 1. So if you started from 1 (meaning the outer text div was just as large as the inner text div) then the resultant ratio would also be one. If it was 1.3 then the ratio plummeted to 0.84. If it was 1.6 then it went to 0.72. If it was 2.00 then it went to 0.5 and so on. I couldn't figure it out so I decided to do a workaround.
If resizing it multiple times made the font-sizes more true then I decided to just resize it with the resizeListener function I was already calling. All I needed to do was resize to the grandparent element in the first part of the function and then resize to the parent element in the second part. The one kicker was that the grandparent-to-child height ratio could not be the same as the frameScale (parent-to-child). So I did this:
if(masterScale = frameScale) {
masterScale = masterScale - 0.5;
}
For whatever reason, 0.5 seems to work well. Maybe this will fail in many different situations but for now it's a good workaround. All I did was resize the container twice. Here is the jsFiddle:
https://jsfiddle.net/j994tnu2/6/
EDIT: This doesn't answer the question though. Why is the beginning frameScale's deviation from 1 determine increasing deviations from 1 after the transformation? If I wanted it perfect I could create an if() else if() tower adjusting for this all the way up to some ratio that wouldn't occur naturally:
1.0-1.04 >>> 1.0
1.05-1.29 >>> 0.94
1.3-1.34 >>> 0.84
1.35-1.6 >>> 0.8
1.61-??? >>> 0.7
1.99-??? >>> 0.49
For whatever reason, subtracting the amount needed to make 1.0 for the resultant ratio from the beginning ratio will adjust the resultant ratio to 1; which doesn't make sense. Here is a jsFiddle doing this very thing and with much better results than resizing to the grandparent element:
https://jsfiddle.net/j994tnu2/9/
I am just trying to get the mouse hover div's position at the right according to the space around. Somehow I am able to do this in first two columns but not for other columns. May be my calculations while writing the condition state are wrong.
Can anyone please help?
JS Fiddle URL:
http://jsfiddle.net/mufeedahmad/2u1zr11f/7/
JS Code:
$('.thumb-over-team li').find('.cover').css({opacity:0});
$('.thumb-over-team li').on('mouseenter', function(){
var $this = $(this),
thisoffset = $this.position().left,
openDivId = $(this).find('.cover'),
thumbContainer = '.thumb-over-team',
speedanim = 200;
if(thisoffset + openDivId.outerWidth() >= $(thumbContainer).outerWidth()){
//thisoffset = $(thumbContainer).outerWidth() - openDivId.outerWidth() - 212;
thisoffset = thisoffset - openDivId.outerWidth()+10;
openDivId.stop().css({'z-index':'9999'}).animate({'opacity':'1', 'left':-thisoffset}, 200);
}else{
openDivId.stop().css({'z-index':'9999'}).animate({'opacity':'1', 'left':'212px'}, 200);
}
}).on('mouseleave', function(){
$(this).find('.cover').stop().css({'z-index':'-1'}).animate({'opacity':'0', 'left':'200px'}, 200);
});
$('.close-parent').on('click', function(){
$(this).parents('.cover').stop().css({'z-index':'-1'}).animate({'opacity':'0', 'left':'200px'}, 200);
});;
In your first conditional, try to calculate the position of the offset as:
thisoffset = ($(thumbContainer).outerWidth() - openDivId.outerWidth() - thisoffset);
That way, you're adjusting the appearing square (.cover) when it doesn't fit inside the container, to be as close possible to its rightmost edge: (maximum width - appearing square width - current li position)
Calculated this way, you can animate it with the new offset in positive:
openDivId.stop().css({'z-index':'9999'}).animate({'opacity':'1', 'left':thisoffset}, 200);
See it working here.
For elements that "almost" fit, the current system isn't completely precise because of what I already pointed out in my previous comment: the appearing square, even if it were at 0 opacity, would still be inside the containing element (($(thumbContainer)) or .thumb-over-team) and it would add its width to the total width of the container.
So your conditional may think that there's enough available space in the container to make the expandable element fit, but that would go out of the screen. As an example, notice that there's a horizontal scrollbar from the very beginning, caused by this effect, where your containing .thumb-over-team element doesn't fit in the screen.
But I would say that more precision in this point would require a fresh new approach to your system where the appearing .cover elements were out of the containing ul .thumb-over-team
Fresh take on the problem, essentially based on the main issue: the expandable text block (.cover) used to add its width to the container (.thumb-over-team). This altered the calculations on available container space, and made the text containers go off screen.
The solution is to make sure the expandable .cover elements aren't contained inside the .thumb-over-team element, so they won't impact the calculations on available width.
Here is a JSFiddle containing this new approach: link.
Explanation of how it works:
The idea was to create a separate element called .cover-container and let's put all the expandable .cover elements in there.
We want to associate every image in the li elements in .thumb-over-team with their appropriate .cover (so the first image triggers the first .cover to show, the second image would show the second cover, and so on.) We achieve is by finding out the index of the element that triggered the event:
thisLiIndex = $this.index() + 1
And then selecting the cover in the matching position:
openDivId = $('.cover-container .cover:nth-child(' + thisLiIndex + ')')
The expandable covers shouldn't interfere with the mouseenter or mouseleave events of .thumb-over-team, so we make it to ignore mouse events via CSS:
.cover-container{pointer-events:none;}
Changing from one image to another would automatically trigger new events, so the expanding covers stay visible when the mouse stays on the images, but close automatically when the mouse exits them.
Since the covers are now outside of $(thumbContainer), openDivID.outerWidth() does not alter $(thumbContainer).outerWidth(), and we can use that safely in our positioning.
If I understand the placement that you want, for covers that fit, the position is the current offset (position of the li element that triggered the event) plus the width of the image and some subtle margin
imageWidth + rightSeparation + thisoffset
And for covers that won't fit inside of the screen, we keep them just inside of the screen
thisoffset = $(thumbContainer).outerWidth() - openDivId.outerWidth();
Have two elements with fixed width (in %).
First element positioned left: 0, second element positioned right: 0;
Need to append some N of elements between these two elements, so each of the new appended elements have same width (depending on available space between main elements).
http://jsfiddle.net/hXUyh/1/
The problem is that new elements are positioned NOT accurately (crossing each other or leaving some extra space between) and NOT consistently with different browser's window sizes.
Please help.
I understand that different browsers will give different output, but this script will be limited to Google Chrome use only.
Try this:
$(document).ready(function() {
for (var i = 0; i < 9; i++) {
$('<div/>').appendTo('body')
}
$(window).resize(function() {
var firstWidth = $('#element-0').width();
var r = ($(window).width() - (firstWidth * 2) - 2) / 9;
$('div').slice(2, 11).each(function(i) {
$(this).css({
left: i == 0 ? firstWidth : firstWidth + r * (i),
width: r
})
})
}).resize()
});
http://jsfiddle.net/yav9Q/
I had similar requirements not too long ago. Without questioning or changing your strategy/code, here is a fiddle showing as close as I can get it:
http://jsfiddle.net/hXUyh/3/
(Note that I haven't catered for resizing as your original code didn't)
The issue that the width() jquery function will round. So your maths will always be a little bit off. I've improved this by using calculations on window.innerWidth, it will be a little bit misaligned because of the floating point widths. Using floating point widths for pixel perfect alignment is not the way to go.
If you want perfect alignment, use padding. Here is an example using the smallest padding possible: http://jsfiddle.net/hXUyh/8/
The maths is much easier if you don't need a border.