Calculating margins

I saw a question elsewhere that got me thinking about doing this in JS: have a div on screen that always has twice as much margin on the right as on the left (so the div is always “off center”, so to speak). To my amazement, I managed to put together some code that seems to do the job, though I’ll bet there are much better ways to do this. So, as a learning exercise, I was wondering if anyone can demonstrate how this code could be improved or made more robust. (I tested it on all the latest Mac browsers, but didn’t bother with IE, so I don’t know if it works there or not.)

Here’s a live example: http://cdpn.io/LIizc


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
	
<style media="all">
body {margin: 0; padding: 0;}
div {width: 600px; height: 600px; background: red; }

</style>
	
</head>
<body>

<div id="test"></div>

<script>
function resize()
{
    var div = document.getElementById("test");
    var windowWidth  = document.documentElement.clientWidth;
    var remainder = windowWidth - div.clientWidth;
    div.style.marginRight = remainder * 2/3 + "px";
    div.style.marginLeft = remainder * 1/3 + "px";
}
window.onresize = resize;
resize();
</script>
</body>
</html>


Hi Ralph,

Two things that occurred to me:

[LIST=1]
[]Do you need to set both the left and the right margin? I think setting just the left would have the same effect.
[
]I would move the assignment of the div variable out of the function. That way you avoid querying the DOM every time the onresize event fires.
[/LIST]That would leave you with this:

function resize(){
  var windowWidth  = document.documentElement.clientWidth,
      remainder = windowWidth - div.clientWidth;
  div.style.marginLeft = remainder * 1/3 + "px";
}

var div = document.getElementById("test");
window.onresize = resize;
resize();

If you wanted to make this more generic, you could pass in a reference to the element that needs repositioning:

function resize(elem){
  var windowWidth  = document.documentElement.clientWidth,
      remainder = windowWidth - elem.clientWidth;
  elem.style.marginLeft = remainder * 1/3 + "px";
}

var div = document.getElementById("test");
window.addEventListener('resize', function(){
  resize(div);
});
resize();

If you were to do this with jQuery:

jQuery.fn.resize = function () {
  this.css("margin-left", ( $(window).width() - this.width() ) * 1/3 + "px");
  return this;
}  
		
var $div = $("#test");
$(window).on("resize", function(){
  $div.resize();
});
$div.resize();

I quite like the $div.resize(); syntax. But this alone wouldn’t be a reason to include jQuery.

Hope that helps.

Thanks Pullo. I really appreciate the reply.

D’uh, how obvious! That’s embarrassing.

I would move the assignment of the div variable out of the function. That way you avoid querying the DOM every time the onresize event fires.

Ah yes, I do need reminders about things like that.

There generic options are definitely preferable. I still find it hard to think in those terms, but these examples are great for getting the hang of them. Presumably the second option needs to end with resize([COLOR="#FF0000"]div[/COLOR]); rather than just resize();?

It’s always nice to see how it’s done in jQuery, too. :slight_smile:

It’s really satisfying to learn from simple examples like this, so I hope you don’t mind me peppering you with them. I’ve been looking at books for a while now, but TBH, I can barely stand to open their pages now. It’s a lot more fun just to pick a simple task, try work out how it’s done, and then ask a question like this. :slight_smile:

Hey, no probs :slight_smile:

Oh yes, well spotted.

Yeah, I quite like the jQuery syntax.
Here’s another nice snippet in a similar vein which centres an element in the middle of the screen.

jQuery.fn.center = function () {
  this.css("position","absolute");
  this.css("top", ( $(window).height() - this.height() ) / 2+$(window).scrollTop() + "px");
  this.css("left", ( $(window).width() - this.width() ) / 2+$(window).scrollLeft() + "px");
  return this;
}  

$("#myDiv").center();

Absolutely not.

That’s exactly how I feel, then, as you start improving, you can start answering questions along the way to consolidate what you have already learnt.