Image manipulation with CSS
Tags: html, css, webdev
Published: 2020-07-20 18:30:12

---
title: Image manipulation with CSS
published: true
description: We discuss 7 ways you can manipulate images using CSS
tags: html, css, webdev
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/wzte7xwzjrtrsebe1znz.png
---

> <b>Original cover photo by [Bruno Emmanuelle](https://unsplash.com/@brunocervera) on [Unsplash](https://unsplash.com/)</b>.

## __Introduction__

Images are found on most websites we have on the internet today in one form or the other from the website _icon_, _infographics_, and images that could make up part of the core website content. Just like anything on a web page, they can be manipulated in one way or the other using several techniques.

We'll discuss __some__ techniques in this article and I'll encourage you to make further research.

Let's begin.

<hr>

We'll discuss 7 manipulation techniques which are listed below, we'll go into detail on how they work and browser support for every CSS property that is used therein:

* Diamond images
* Blurred images
* Two image overlay with `mix-blend-mode`
* Black and white image
* Rounded corners with `border-radius`
* Curved corner images
* Side-by-Side alternate image

## __Diamond images__

What I termed diamond images are images which are displayed in the form close to the shape of a diamond. The images will have four sides and if you are familiar with [_isometric_](https://en.wikipedia.org/wiki/Isometric_projection) angles, they'll align like objects in a `30 degree`or `45 degree` _plane_.

The main ingredient here is the `clip-path` CSS property.

### __What is the `clip-path` property?__

The `clip-path` property creates a region called a __clipping__ that dictates what part of an element is shown on screen. It can accept the name of the following shapes as a value:

* _polygon_
* _ellipse_
* _circle_

The shape accepts parameters which dictates the final output of the element. For this article, we are interested in the _polygon_ shape which is written as `polygon()` when used as a value of the `clip-path` property.

The following code will get us the desired effect.

```css
.image-selector {
    clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
```
### __How it works__

The values passed to the `polygon()` function are coordinates that tells `clip-path` which part of the image should be _chopped_ off. Each comma separated values are _x_ and _y_ coordinates along each four sides of the image.

To understand what I am saying, have a look at the image below:

![Coordinates of a polygon](https://dev-to-uploads.s3.amazonaws.com/i/p4qxo6q3hj81wjfsyrd4.png)<figcaption>Coordinates of clip-path. Source: [Beyond paper](https://beyond-paper.com/clip-path-polygons-explained/)</figcaption> 

From the image it is evident that the coordinates in a _clockwise_ manner are the following:

*  _x:0, y:0_
*  _x:100, y0_
*  _x:100, y:100_
*  _x:0, y:100_

Therefore, our `clip-path` value: `polygon(50% 0, 100% 50%, 50% 100%, 0 50%)` can be translated to:

* _Move 50% along the x-axis, this will align  at the center_.
* _While the top x-axis is at 100%, move 50% on the right y-axis, this will take us to the middle of the right y-axis_.
* _Then move to 50% of the bottom x-axis, this will be the center of the bottom x-axis_.
* _Then move back to the center of the left y-axis at 50%_.

The steps above becomes complex depending on the shape you want to create.

### __Expected output__

Following the steps above, you should get an output similar to the diamond image below:

![Diamond shaped image](https://dev-to-uploads.s3.amazonaws.com/i/33v6s8wlsoi88pr15utb.png)<figcaption>Diamond image</figcaption>

_Mind you, I added a blue border to the image container to show the points where the clipping occurs_.

As an exercise and to test if you understand the entire process, try to replicate the image below.

![Arrow shaped image](https://dev-to-uploads.s3.amazonaws.com/i/zfda2yki4lfylt9pn923.png)<figcaption>Arrow image</figcaption>

Developers love tooling and you should not be surprised someone already made a tool to generate some commonly used shapes. The tool is called [Clippy](https://bennettfeely.com/clippy/).

### __Browser support__

|       Chrome        | Firefox |     Safari      |  Edge  |        Opera        |
| :-----------------: | :-----: | :-------------: | :----: | :-----------------: |
| 55.0, 23.0 -webkit- |  54.0   | 9.1, 6.1-webkit | 12.0 | 42.0, 15.0 -webkit- |


## __Blurred images__

If you'll like to achieve a blurred image effect, all you need is one line of code.

```css
.image-selector {
    filter: blur(5px);
}
```

### __How it works__

Mozilla Developer Networks explains how `filter` works perfectly:

> The **`filter`** [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS) property applies graphical effects like blur or color shift to an  element. Filters are commonly used to adjust the rendering of images,  backgrounds, and borders.

### __Expected output__

![An image of a Blurred sunset image](https://dev-to-uploads.s3.amazonaws.com/i/an03l6bwzd9niu1ubehl.png)<figcaption>Blurred image</figcaption>

### __Browser support__

| Chrome              | Firefox |          Safari | Edge | Opera               |
| ------------------- | :-----: | --------------: | ---: | ------------------- |
| 53.0, 18.0 -webkit- |  35.0   | 9.1, 6.0-webkit | 13.0 | 40.0, 15.0 -webkit- |

## __Two image overlay with `mix-blend-mode`__

CSS positioning allows developers to place element anywhere on the web page, even on another element. With the addition of the `mix-blend-mode` property we can create a stunning effect.

The trick is to place an image over another, and then we'll apply a `mix-blend-mode` to the image on top.

Your HTML should be similar to the following:

```html
<div>
    <img src="img/the-name-of-your-image.jpg" />
    <img src="img/the-name-of-your-image.jpg" />
</div>
```

And your CSS will be:

```css
img {
    width: 100%;
}

img:first-child { /* Grab the first image */
    position: absolute;
    mix-blend-mode: soft-light;
}
```

### __How it works__

Mozilla Developer Network explains it nicely:

> The **`mix-blend-mode`** [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS) property sets how an element's content should blend with the content of the element's parent and the element's background.

### __Expected output__

![An image of laptop computers with a sunset background](https://dev-to-uploads.s3.amazonaws.com/i/hefhukejm9vbb3eogxau.png)<figcaption>Images with mix-blend-mode</figcaption>

_The two images used are from Unsplash. Search for [sunset](https://unsplash.com/s/photos/sunset) and [download the laptop image from Dell XPS official account](https://unsplash.com/photos/B5rNNkGtRXI)_.

### __Browser support__

| Chrome | Firefox | Safari |     Edge      | Opera |
| :----: | :-----: | :----: | :-----------: | :---: |
|  41.0  |  32.0   |  8.0   | Not supported | 35.0  |

## __Black and White image__

The title of the manipulation says it all, we'll take a normal image and convert it to a black and white photo using a combination of CSS filters.

In my opinion, the code is easy to understand.

```css
.black-and-white-image {
    filter: grayscale(1) contrast(20);
}
```

### __How it works__

The filter converts the image to a [_grayscale_](https://en.wikipedia.org/wiki/Grayscale) and we set the [_contrast_](https://skylum.com/blog/understanding-contrast-in-photography) to `20`. This creates the desired effect.

### __Expected output__

![Picture of a man with a camera](https://dev-to-uploads.s3.amazonaws.com/i/2itl8owy74m62ugtyaer.png)<figcaption>A colored and a black and white photo</figcaption>

_Mind you, in the image above I placed the original image beside the edited image for easy comparison_.

### __Browser support__

| Chrome              | Firefox |          Safari | Edge | Opera               |
| ------------------- | :-----: | --------------: | ---: | ------------------- |
| 53.0, 18.0 -webkit- |  35.0   | 9.1, 6.0-webkit | 13.0 | 40.0, 15.0 -webkit- |

## __Rounded corners with `border radius`__

The `border-radius` property is used to change the radius of an element on a web page. An appropriate candidate is an image. It's also a shorthand for four other properties namely:

* `border-top-left-radius`
* `border-top-right-radius`
* `border-bottom-right-radius`
* `border-bottom-left-radius`

The code to generate our weird looking image (shown later) is given below:

```css
/**
 * We apply a radius to all four sides of the
 * image.
 */
.image-selector {
    border-radius: 130px 160px 90px 220px;
}
```


### __How it works__

_I think the code is self-explanatory_.

### __Expected output__

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/2lieg007dkzq30w4nx3v.png)<figcaption>Image with rounded corners</figcaption>

### __Browser support__

| Chrome            |    Firefox     |           Safari | Edge | Opera |
| ----------------- | :------------: | ---------------: | ---: | ----- |
| 5.0, 4.0 -webkit- | 4.0, 3.0 -moz- | 5.0, 3.1-webkit- |  9.0 | 10.5  |

## __Curved corner images__

To get our _curved_ corner images, we will revisit the `clip-path` property discussed earlier in this post. The logic behind the generation of the corners is the same as detailed under the section titled "Diamond images" with one addition, the `calc` function.

The `calc` function is used to make the arithmetic calculation along the _top x-axis_ and the bottom _x-axis_ easier.

Since the axis is equal to `100%` and we start clipping on the _x-axis_ at `20px`, the `clip-path` function is used to deduct `20px` on each side of the top _x-axis_ and bottom _x-axis_.

```css
.image-selector {
    max-width: 100%;
    clip-path: polygon(20px 0,
                       calc(100% - 20px) 0,
                       100% 20px,
                       100% calc(100% - 20px),
                       calc(100% - 20px) 100%,
                       20px 100%,
                       0 calc(100% - 20px),
                       0 20px);
}
```

### __How it works__

_This is detailed in the last paragraph. If you need further explanation, let me know in the comments section._

### __Expected output__

![An image of a sunset](https://dev-to-uploads.s3.amazonaws.com/i/92zyjrizxd1typ93lejn.png)<figcaption>Curved corner images</figcaption>

### __Browser support__

|       Chrome        | Firefox |     Safari      |   Edge |        Opera        |
| :-----------------: | :-----: | :-------------: | -----: | :-----------------: |
| 55.0, 23.0 -webkit- |  54.0   | 9.1, 6.1-webkit | 12.0 | 42.0, 15.0 -webkit- |

## __Side-by-Side alternate image__

What I termed as _side-by-side alternate images_ is when half of an image is colored and the other half is not _or_ in a different color.

Now, you might wonder how we are going to this, but if you have read this article up to this point you'll realize we have _almost_ everything to achieve our aim. They are:

* `clip-path`
* `filter`

I said _almost_ which means we will need additional CSS properties which are:

* `z-index`
* `margin-left`

How do they fit together? I'll save you some time, the HTML and CSS code is given below and the explanation follows it.

```html
<div class="img-container">
    <img src="img/the-name-of-your-image.jpg" class="un-altered" />
    <img src="img/the-name-of-your-image.jpg" class="altered" />
</div>
```

```css
.image-selector {
    max-width: 100%;  /* This is necesary for Chrome browsers. */
}

.img-container {
    display: flex;
    width: 70vw;
    margin: 0 auto;
}

.un-altered {
    clip-path: polygon(50% 0, 50% 100%, 0 100%, 0 0);
    z-index: 1;
}

.altered {
    margin-left: -100%;  /* Pull the image to the left */
    filter: grayscale(1) contrast(1);
}
```

### __How it works__

First, we will need __two images__ (in this case, __the same image of the same size__) to pull this off.

The images will be differentiated by the following:

* The original image will have a _class_ attribute of `un-altered`.
* The image that will be edited with CSS filters will have a _class_ attribute of `altered`.

Second, we need to display the image _side-by-side_, this is easy to achieve with a Flexbox layout. All we need is `display: flex` .

![Pictures of a smiling man with beard](https://dev-to-uploads.s3.amazonaws.com/i/qj2hz3l0utnaprbcwxz0.png)<figcaption>Image layout with Flexbox</figcaption>

Next, we have to reduce the size of the image with the `un-altered` class using the `clip-path` property. What we will do is this: the image will be _clipped_ into half, later, we will _join_ this half to the image with the `altered` class.

![Pictures of a smiling man with beard](https://dev-to-uploads.s3.amazonaws.com/i/syr9fns1vu4eccugwvub.png)<figcaption>Clipped image</figcaption>

Moving forward, we will have to pull the image with the `altered` class towards the clipped image. This is possible by reducing its `margin-left` property to `-100%`. __This creates a problem__.

Both images are of the same size, therefore, when we move the image with the `altered` class it will definitely cover the other image with the `un-altered` class and they will now appear to be a _single_ image, but __they are not__.

![Pictures of a smiling man with beard](https://dev-to-uploads.s3.amazonaws.com/i/dpmm60d385fqgj62smp0.jpg)<figcaption>Original image covering the clipped image</figcaption>

Next, we need to add a _grayscale_ and _contrast_ _filters_ to the image with the `altered` class. The entire image is now _grayscale_, __this is not what we want__.

![Pictures of a smiling man with beard](https://dev-to-uploads.s3.amazonaws.com/i/ztdph17y1k09fhd7r8rb.png)<figcaption>A grayscale image</figcaption>

What we really want is for _half_ of the image with the `altered` class to _slide_ under the image with the `un-altered` _class_. This means the image with the `un-altered` _class_ that we _clipped_ earlier has to be on _top_ of the image with the `altered` _class_.

Thanks to the `z-index` property, this is super easy.

The image that with the `un-altered` _class_ will have a higher `z-index` than the image with the `altered` class.

This creates the desired visual effect where the original image is on one side and the edited image is another side. __In the end the image appears to be a single image with two different colors__. That is awesome!.

### __Expected output__

![Picture of a smiling man with beard](https://dev-to-uploads.s3.amazonaws.com/i/sz82et4vym3yhzi96aeq.jpg)<figcaption>An altered side-by-side image</figcaption>

_The image is courtesy of [Reza Biazar](https://unsplash.com/@biazar) on [Unsplash](https://unsplash.com/)_.

### __Browser support__

_Check the support table for `filter` and `clip-path` discussed in different sections of this article_.

### __Side note__

Kindly note the following:

* This technique fails when you reduce the browser _zoom_ level to `30%`. At the point it becomes evident that the image is indeed not a single image 🙃.

* It does not work in Internet Explorer 😉 .

## __Conclusion__

We have barely scratched the surface of image manipulation in CSS, I'll encourage further research and if you find anything interesting kindly share it in the comments.

## __References__

* 📹 [AwesomeCSS #1 | Apply Image Filters Just Using CSS](https://www.youtube.com/watch?v=GmgvpMT2BJM&feature=youtu.be)
* 📹 [Image manipulation with CSS Mix blend mode](https://www.youtube.com/watch?v=u1gsQNa4wfk)
* 📚 [Clip-Path Polygons Explained](https://beyond-paper.com/clip-path-polygons-explained/)
* 📚 [CSS border-radius Property](https://www.w3schools.com/cssref/css3_pr_border-radius.asp)
* 📚 [CSS filter Property](https://www.w3schools.com/cssref/css3_pr_filter.asp)
* 📚 [CSS clip-path](https://www.w3schools.com/cssref/css3_pr_clip-path.asp)

## __Further reading__

Explore the following article:

* [Editing Images in CSS: Combining Techniques](https://code.tutsplus.com/tutorials/editing-images-in-css-combining-techniques--cms-26061)

## __Credits__

All browser support table is courtesy of [W3Schools](https://w3schools.com).

_Updated August 15, 2020: Updated browser support tables._