Imagine you are in an interview and you get asked "can you implement bubble sort"...and you answer the interviewer "sure, do you want that in JavaScript or CSS".
What a flex would that be?
Now, I know what you are thinking. "no interviewer will be impressed by you creating an animation that simulates bubble sort". And you would be right!
But what if we could create a functioning bubble sort algorithm...in pure CSS...and add visualisations to it?
Well, you have come to the right place!
The Demo
Instructions: There are 5 values at the top of the :root
element:
:root{
--val1: 12;
--val2: 16;
--val3: 9;
--val4: 14;
--val5: 7;
These are our unsorted array!
So the above represents: [12,16,9,14,7]
.
And you can change those values (any value between 0 and 20) and then press "run" in the Codepen UI and it will actually sort them for you!
warning: on mobile the last few animations might not play and just go blank. On PC your fan may spin up!
This is a limitation of using so many calculations that rely on previous calculations...I am not sure if it runs out of memory or what, but I defo pushed the limits of CSS here!
Anyway, with the warnings out of the way, give it a go (you may need to press "rerun" in the bottom right as the animation only plays once)!
Explanation
Look, this is silly, so I am not going to do a tutorial, but there are a couple of things that are interesting:
Getting a boolean for v2 > v1
--is-1-greater-2-step-1: Min(1, Max(var(--arr1s0) - var(--arr2s0), 0));
Looks complicated, but it isn't, we are performing the following operations:
- subtract the value of position 2 from the value of position 1 in our array. (lets call this "diff1and2" for ease)
- find the maximum of "diff1and2" and 0. We do this as a way of saying "if 1 is bigger than 2, we want a positive value, but if 2 is bigger than 1 we want to return 0". Lets call the result of this "1greaterOrZero".
- then we take "OneGreaterOrZero " and make sure it is not greater than 1 by using
Min
. So if "OneGreaterOrZero" was 6, we would reduce that to 1, but if it was 0 then we would return 0.
Still confused? Here it is in JS effectively:
let pos1 = 7;
let pos2 = 15;
let diff1and2 = pos1 - pos2;
//if "diff1and2" is negative the next step will change it to 0;
let OneGreaterOrZero = Math.max(diff1and2, 0);
let result = Math.min(1, OneGreaterOrZero);
console.log(diff1and2, OneGreaterOrZero, result); //always between 0 and 1 as false / true representation.
swapping array positions
So how do we swap positions in our "array"?
For bubble sort to work we need to be able to swap 2 values if the first value is larger than the second.
We can't do any temp variable magic like we would in JS.
Well, that is what this is for:
--arr1s1: calc(var(--is-2-greater-1-step-1) * var(--arr1s0) + var(--is-1-greater-2-step-1) * var(--arr2s0));
--arr2s1: calc(var(--is-1-greater-2-step-1) * var(--arr1s0) + var(--is-2-greater-1-step-1) * var(--arr2s0));
Yet again, looks complicated, is actually reasonably simple in principle.
In our previous "function", we created a boolean to see if 1 was greater than 2. So we have either a 1 or a 0 there.
We can also easily get the inverse of this:
--is-2-greater-1-step-1: (1 - var(--is-1-greater-2-step-1));
The beauty of this is that we can now do the following trick:
// in bubble sort, if 1
origArray = [7,2];
// we run our previous functions to get our 2 variables:
oneIsGreater = 1;
twoIsGreater = 0;
// we can now multiply the values together. If [2] is greater than one then we will return the same value. But if [1] is greater than [2] then we will swap the values.
newArray[0] = (twoIsGreater * origArray[0]) + (oneIsGreater * origArray[1]);
newArray[1] = (oneIsGreater * origArray[0]) + (twoIsGreater * origArray[1]);
// which is the same as this:
newArray[0] = 0 * 7 + 1 * 2; //2
newArray[1] = 1 * 7 + 0 * 2; //7
Neat trick huh? and if oneIsGreater
and twoIsGreater
were swapped then it would just return the original values!
origArray = [7,2];
oneIsGreater = 0;
twoIsGreater = 1;
//same "function"
newArray[0] = (twoIsGreater * origArray[0]) + (oneIsGreater * origArray[1]);
newArray[1] = (oneIsGreater * origArray[0]) + (twoIsGreater * origArray[1]);
// which is the same as this:
newArray[0] = 1 * 7 + 0 * 2; //7
newArray[1] = 0 * 7 + 1 * 2; //2
And that is effectively all we need to do a bubble sort!
The only reason we have so much CSS is because we cannot do loops in vanilla CSS (yet). So we have to manually write out the swaps for each stage of bubble sort:
- check and if needed swap 1 and 2
- check and if needed swap 2 and 3
- check and if needed swap 3 and 4
- check and if needed swap 4 and 5
- check and if needed swap 1 and 2
- check and if needed swap 2 and 3
- check and if needed swap 3 and 4
- check and if needed swap 1 and 2
- check and if needed swap 2 and 3
- check and if needed swap 1 and 2
That's all folks!
As I said, not a tutorial. But I did want to introduce some interesting CSS "switches" and "booleans" that may become useful in some strange scenario in the future for you!
I hope you enjoy my silliness.
Now I just have to wait for someone to ask me if I can implement Bubble sort so I can flex on them with my CSS silliness! ๐คฃ๐
Top comments (24)
Bogosort next ๐ฅ
Canvas of babel with pure CSS ๐
Haha, that scares even me! ๐คฃ๐
Haha, I might actually do it. Although I may run into a limitation on the number of iterations etc.
Fun idea though! ๐คฃ๐
Or, if you're lucky enough, it might all get sorted in the first try. Literally the only sorting algorithm that has the potential to do so ๐ ๐ ๐
Anywhere from O(1) to O(infinity) ๐คฃ๐
๐
You sir are an evil genius..
Next up we expect to see your implementation of Doom in CSS.
๐ if this was a valid reaction I'd have used it rather than heart.
There is a proposal for css var arrays (with CSS random too) so you might have to revisit this someday ๐
Yeah that would probably make this 200 times easier and actually performant...but then it wouldn't be fun anymore! ๐คฃ๐
What about the time complexity for this?
O(n2) it is just bubble sort! ๐คฃ๐
๐โค๏ธ
This is amazing ๐คฏ I'm impressed that you didn't mess up that very copy&paste-intensive code (if you did, I bet it was hell to debug) ๐
No way๐
aint no way bruh...
Waaaay doood! ๐คฃ๐
Wow... that is crazy but also impressive, and all that CSS even passes CSS HTML Validator with no errors!
My CSS is always valid...even the stuff that isn't useful like this! ๐คฃ๐
Wow thats insane!! Fascinating post!! You can definitley do some cool stuff with CSS if you know what you're doing!
Yeah, but at the same time, it is far less stressful to do it in a proper language! ๐คฃ๐
ow congrats, great post!
๐๐ผ๐
Ooohhh, we are number 9 in the series!
Number 10 should be fun...Conway's game of life...in pure HTML! ๐คฃ๐