Abstraction is an important concept in any language. You can think of CSS as a way of abstracting the design away from the content of a site. This makes the code for both much easier to read, understand and maintain. Javascript is a way of abstracting away the functionality of a site, and jQuery a further abstraction making common tasks much much easier. Writing plugins for jQuery is yet another deeper abstraction which makes your jQuery easier to write and understand.
To illustrate this idea, let’s build an jQuery plugin. While we’re at it, it might as well be something useful! We’re going to call it MaxSide. The idea here is to take any page element and resize it, making the length of its longest side a value you determine. For example, if you have an image that is 300x180px you could call MaxSide on it with a value of 100 and the resulting image would be 100x60px (it maintains its ratio).
Let’s get to it.
Doing it Without a Plugin
Let’s put three images on the page, one 200x200px, one 200x50px, and one 50x200px.
<body>
<img src="images/200x200.jpg" alt="" />
<img src="images/200x50.jpg" alt="" />
<img src="images/50x200.jpg" alt="" />
</body>
We want to run some jQuery on these images so that each of their longest sides becomes 100. 200x200px becomes 100x100px, 200x50px becomes 100x25px, and 50x200px becomes 25x100px.
Let’s include jQuery on our page (in the <head> section) and write the code that will make this happen:
<script type="text/javascript" src="../jquery-1.2.6.min.js"></script>
<script type="text/javascript">
// don't run until all images are loaded
$(window).bind("load", function() {
// run on every image on the page
$("img").each(function(){
// set a variable for this, quicker
var $this = $(this);
// maximum length is hard-coded here
var $maximum = 100;
// jQuery 1.2.6 has "dimensions" built-in
var $thewidth = $(this).width();
var $theheight = $(this).height();
if ($thewidth >= $theheight) {
if ($thewidth >= $maximum) {
$(this).attr({
width: $maximum
});
}
}
if ($theheight >= $thewidth) {
if ($theheight >= $maximum) {
$(this).attr({
height: $maximum
});
}
}
});
});
</script>
In plain English, this reads: “Look at every image on the page. If it is wider than it is tall, make it’s width 100. If it’s taller than it is wide, make it’s height 100.”
Works like a charm, see the example without the plugin.
Doing it With a Plugin
There are a couple of problems with doing the “without the plugin” way. For one, it really dirties up our page. We should really get all that code off of our HTML file, as that is where our content lives and we are trying to abstract here. Two, the “MaxSide” is hard-coded here. What if we want to use this same bit on the page but use a different MaxSide value. We would have to repeat very similar code. Never a good idea.
jQuery makes it easy for us to write our own functions in the form of plugins, to abstract away code like this. Take a look at the new code in our header, using the plugin:
<script type="text/javascript" src="jquery-1.2.6.min.js"></script>
<script type="text/javascript" src="jquery.maxside.js"></script>
<script type="text/javascript">
$(window).bind("load", function() {
$("img").maxSide({ maxSide: "100" });
});
</script>
A lot simpler, eh? But not only simpler, but now we could call the maxSide function on different page elements and with different values to boot.
jQuery.fn.maxSide = function(settings) {
// if no paramaters supplied...
settings = jQuery.extend({
maxSide: 100
}, settings);
return this.each(function(){
var maximum = settings.maxSide;
var thing = jQuery(this);
var thewidth = thing.width();
var theheight = thing.height();
if (thewidth >= theheight) {
if (thewidth >= maximum) {
thing.attr({
width: maximum
});
}
}
if (theheight >= thewidth) {
if (theheight >= maximum) {
thing.attr({
height: maximum
});
}
}
});
};
Notice the code really isn’t all that different here. There are a couple of important things to note though.
- This plugin is built to do its thing on every page element that matches what you call it on. Hence the “each” function. If you wish to write a plugin which only effects a single page element, it is even easier. Omit the “each” function and write regular ol’ jQuery but include a “return this;” line at the end.
- The “settings” bit at the beginning of the function handles the event in which the function is given no parameter (it defaults to 100px). You could technically call this function with just .maxSide(); if you wanted.
- If you are using this function on images, it should only be called after the window load event. Many jQuery functions are called when the DOM is ready instead, which is much faster, but the width and height calculations will fail if the images are not fully loaded yet (very probable).
- Variables inside the plugin don’t need the “$”.
Clean and concise. Excellent tut on authoring plugins.
$(window).bind(“load”, function() {
//something happens here
}
I need to the something that happens to happen after the images had loaded, as u have stated,
but in firefox it’s just happening after the DOM have been loaded (before the images had).
I mainly use opera and its OK there.
PS:the difrence in my code is that i use images as background with css, so apperantly opera takes them into account, but firefox not
If you want to do something when the DOM is ready:
If you want to do something when the page is loaded:
Are you saying that even while using the second option here that it’s firing too early? If that’s the case, that’s an interesting problem I’ve never run across.
yep, it too early.
But only in firefox, Opera and IE are fine. And i guess it only for the images that a background (and in my sites usually nearly all the images are background ).
And i still haven’t updated Firefox –I kinda don’t like it :)
Hah, it’s fixed in Firefox3.
Ok , that’s good … I won’t have to write some weird solution.
Sorry for the spelling of the last comment :)
Nice for this plugin. Please note that actually the download page give a 404 error. I had to download the js from the sample page.
A little usage advice: Since I tried with a big logo, imaging to use this plugin where there’s a logo that can’t be resized before uploading and can be very large… When loading the page, the big image version first appars, then resizes to the right value thanks to the plugin. If you give a display:none and add a $(“#logo”).show(); after $(“#logo”).maxSide({ maxSide: “xx” }); your logo will stay hidden until resized :)
@Tinny: Sure, that’s one way you could fix that problem. The problem arises though if the user has Javascript turned off, they won’t see the images period then. That would be at your discretion, but generally a bad idea. Another way to do it would be to hide the image when the DOM is ready, but then only call maxSize when the page is loaded.
It’ true. With your solution it would be perfect. Maybe the maxside function before the show can be even better (talking about milliseconds…)
A nice feature would be a different maximum for width and height.
Excellent plugin. Is there anyway to modify it so that it only resizes images that exceeds a certain width? For example resize any image that is wider than 300px to be 300px wide. Anything smaller than 300px wide isn’t resized.
This looks great and very close to what i am looking for.
Is there any way to modify this code to look for all images in a div and if they are over 600px wide or to wide for the containing div resive them to be only 500px wide and maintain the proportions?
I have been looking every where for this type of functionality.
Any help would be greatly appreciated! :)
AAron I think you need to combine this plugin with the dimensions plugin http://docs.jquery.com/Plugins/dimensions and do an each for all images within the div, then and if based on the size
something like
$.(“#IDOFTHEDIV”).children(“img”).each(function(){
if ((this).innerWidth() > 600)
{
$(this).maxSide({ maxSide: “500” });
}
});
Not tried but I think it should work
Thank you so much Tinny for the quick reply! wow!
I have downloaded the dimensions plugin and tried the code above but am getting an error.
This is what I have.
jQuery(document).ready(function(){
$.(“.Content”).children(“img”).each(function(){
if ((this).innerWidth() > 550)
{
$(this).maxSide({ maxSide: 500 });
}
});
});
The error says “Expected Identifier” on line 5 which is this line
if ((this).innerWidth() > 550)
Any ideas or help would be so greatly appreciated!
Thanks again for the help!
I just reallized i need to use your plugin maxside as well…oops!
BUT…i have included your plugin along with the dimensions plugin and have changed the call to…
$(window).bind(“load”, function() {
$.(“.Content .p-20”).children(“img”).each(function(){
if ((this).innerWidth() > 550) {
$(this).maxSide({ maxSide: “500” });
}
});
});
But i still get the same error.