Add post: image zoom without jquery
This commit is contained in:
parent
c77992c863
commit
bee91101bd
|
@ -5,7 +5,7 @@ copyright = "Ariejan de Vroom"
|
|||
|
||||
PygmentsCodeFences = true
|
||||
pygmentsuseclasses = false
|
||||
pygmentsstyle = "arduino"
|
||||
pygmentsstyle = "pastie"
|
||||
|
||||
[author]
|
||||
name = "Ariejan de Vroom"
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
+++
|
||||
date = "2017-03-20"
|
||||
title = "Image Zoom with plain JavaScript and CSS"
|
||||
tags = ["javascript", "css"]
|
||||
description = "I'm a back-end developer and rarely dabble in the fine art of writing JavaScript. This site still uses jQuery for handling image zooming. No more!"
|
||||
slug = "image-zoom-with-plain-javascript-and-css"
|
||||
+++
|
||||
|
||||
The premise is simple. A post may contain images. These images are restricted in rendered size to
|
||||
keep the flow of the page in tact. Clicking an image allows you to zoom in. Here's an example:
|
||||
|
||||
_Go ahead, click that bunny!_
|
||||
|
||||
![Sample zoomable image](/img/bunny.jpg)
|
||||
|
||||
## The CSS
|
||||
|
||||
Let's get the CSS out of the way first. The selector used is `article img`, which means
|
||||
any image in the post. By default I limit it to a maximum width of its parent container.
|
||||
Also, I change the cursor to a pointer, to indicate you can click on the image, like a link.
|
||||
|
||||
``` css
|
||||
article img {
|
||||
max-width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
```
|
||||
|
||||
Then there are images with the `zoomed` class. This is still the same image element,
|
||||
but with an additional class:
|
||||
|
||||
``` css
|
||||
article img.zoomed {
|
||||
position: fixed;
|
||||
|
||||
top: 5vh;
|
||||
bottom: 5vh;
|
||||
left: 5vw;
|
||||
right: 5vw;
|
||||
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
|
||||
margin: auto;
|
||||
|
||||
border: 4px solid #000
|
||||
}
|
||||
```
|
||||
|
||||
Okay, that's a bit more CSS, but this basically overlays the image on to the page and adds some
|
||||
whitespace around it.
|
||||
|
||||
The trick to zooming is adding the `zoomed` class to the `img` element. Zooming out means
|
||||
removing that `zoomed` class again.
|
||||
|
||||
Now, on to the JavaScript...
|
||||
|
||||
## The jQuery solution
|
||||
|
||||
For years now jQuery has been my go-to tool for anything JavaScript, mainly because it
|
||||
comes bundled with Rails. (Yes, I used prototype as well in the old days.)
|
||||
|
||||
The jQuery solution is as you rather straight forward. Wait for the DOM to be loaded,
|
||||
and handle `click` events on all `article img` elements. When clicked, toggle the `zoomed`
|
||||
class.
|
||||
|
||||
``` javascript
|
||||
$(function() {
|
||||
$(document).on('click', 'article img', function() {
|
||||
$(this).toggleClass('zoomed');
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Because I'm a keyboard user (Vim, not Emacs, thank you), I prefer to map <kbd>ESC</kbd> to
|
||||
also close any zoomed imaged.
|
||||
|
||||
``` javascript
|
||||
$(function() {
|
||||
$(document).keyup(function(e) {
|
||||
if (e.keyCode == 27) {
|
||||
$('img.zoomed').each(function(idx) {
|
||||
$(this).toggleClass('zoomed');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Again, hook into the `keyup` event, check if <kbd>ESC</kbd> was pressed and toggle
|
||||
the `zoomed` class for all zoomed in images.
|
||||
|
||||
But, using jQuery means adding an extra dependency: 1 extra HTTP request and 85kB download for you.
|
||||
Also, the few friends I have who practice JavaScript tell me that _pure_ JavaScript is the way to
|
||||
go these days. So, let's try!
|
||||
|
||||
## The JavaScript solution
|
||||
|
||||
With some help from the [You Might Not Need jQuery](http://youmightnotneedjquery.com/) website,
|
||||
I managed to drop the 85kB big jQuery dependency and rewrite the above functionality in plain old
|
||||
JavaScript.
|
||||
|
||||
First, let's write a function that waits for the DOM to load.
|
||||
|
||||
``` javascript
|
||||
function ready(fn) {
|
||||
if (document.readyState != 'loading') {
|
||||
fn();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', fn);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This was taken straight from You Might Not Need jQuery to wrap any functions you want to run
|
||||
when the document has loaded fully.
|
||||
|
||||
Next I wrote a function to handle toggling the `zoomed` CSS class on the images:
|
||||
|
||||
``` javascript
|
||||
function imageClick(e) {
|
||||
e.preventDefault();
|
||||
this.classList.toggle('zoomed');
|
||||
}
|
||||
```
|
||||
|
||||
It turns out that JavaScript is more than capable of toggling classes on its own.
|
||||
|
||||
While we're at it, let's also write the function that handles the <kbd>ESC</kbd> presses.
|
||||
|
||||
``` javascript
|
||||
function handleEsc(e) {
|
||||
if (e.keyCode == 27) {
|
||||
var zoomedImages = document.querySelectorAll('img.zoomed');
|
||||
Array.prototype.forEach.call(zoomedImages, function(el, i) {
|
||||
el.classList.toggle('zoomed');
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is a bit more involed. I still check for the proper `keyCode`, and then proceed to
|
||||
find all zoomed images using `document.querySelectorAll`. It's really that easy.
|
||||
|
||||
Next I use the `Array` prototype to map a function to each zoomed image. That function simply
|
||||
toggles the `zoomed` class, just like `imageClick` does.
|
||||
|
||||
What remains is nothing more than some glue to put the above fuctions together.
|
||||
|
||||
``` javascript
|
||||
ready(function() {
|
||||
var images = document.querySelectorAll('article img');
|
||||
Array.prototype.forEach.call(images, function(el, i) {
|
||||
el.addEventListener('click', imageClick);
|
||||
});
|
||||
|
||||
document.addEventListener('keyup', handleEsc);
|
||||
});
|
||||
```
|
||||
|
||||
Here I use the `ready` function I wrote. Just like `handleEsc`, I find all
|
||||
`article img` elements and add the event listener for clicks. Then I also
|
||||
add an event listener for the <kbd>ESC</kbd> key.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Rewriting a trivial piece of jQuery code to plain JavaScript appears to be more
|
||||
than worth the while. Besides the warm fuzzy feeling of dumping jQuery, it saves
|
||||
quite a few kilobytes from each page on devroom.io. Especially for mobile users
|
||||
this matters.
|
||||
|
||||
`git` says 11 deletions (bye, jQuery) and 27 additions (hello, JavaScript). This does
|
||||
not tell the full story, as one of these deleted lines is this one:
|
||||
|
||||
``` html
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||
```
|
||||
|
||||
I can highly recommend you take a closer look at what your jQuery code is _actually doing_
|
||||
and consider moving away from unnecessary dependencies. Yay for lean and mean web pages!
|
||||
|
BIN
static/img/bunny.jpg
Normal file
BIN
static/img/bunny.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 MiB |
Loading…
Reference in New Issue
Block a user