You can Follow me on Twitter to get tutorials, JavaScript tips, etc.

CSS Visual Dictionary
Contains visual diagrams for every single CSS property in common use.medium.com

The best tutorials come from finishing real projects. When the project is done, I like sharing what I learned.

This time, the project is my CSS flex layout designer. I will explain how I created it from start to finish and provide example source code below.

Open Flex Layout Designer

This is the instance of flex class we’re going to code in this tutorial.

That’s what we’re building in this tutorial. You can also spawn multiple instances of it at will on the same page with different default parameters.

Here is the Open Flex Layout Designer < click to try it live again:

Open Flex Layout Designer

I think it’s a fun project because the built-in CSS flex functionality cuts out most of the work for us. The most difficult thing here is writing the “drag and drop” code, but still, it’s not that hard.

To create this flex layout designer we will briefly use jQuery for cross-browser click events and jQuery.css method to dynamically set CSS properties to our flex items while they are being resized.

FIRST THINGS FIRST. Why are you creating your application? Why is it needed? (Is it?)

It’s fine if you get excited about ideas. But to write effective software that people actually need, you must never write a line of code without first asking if there is a need for what you are about to create.

You always start in the same way.

Find an existing problem that needs to be solved. In my case, I was able to answer this question. That’s because most flex tutorials I found online were either too limited or contained explanations using static images.

I mean, come on. This is flex. The name itself alludes to the fact that things will be flexing. That is, resizing, scaling, changing. So why all the static image tutorials for flex?

This didn’t sit well with me. I knew that to create a truly useful tool that has high educational value, an interactive approach was overdue.

Your application idea should start with an abstract vision. Usually, it is something you get excited about. But remember that your software must also solve a real, existing problem.

For me, I wanted to create a tool or generator that doesn’t exist yet. Something you wish existed for personal reasons.

In this case, the CSS flex layout examples I thought of, should have the ability to add and remove flex items from the list dynamically.

First, I Plan Some Global Variables

Global variables are usually shunned by professional software engineers and developers. That’s because modular software design (you know, when you use someone else’s code, and they defined a global variable names that you already used in your own code) will fail if you use them in your own library.

But for the purpose of this tutorial, we will use global variables to learn how to create something. We are not distributing this code as a library. We’re not sharing it with other coders. It will only be used on one site and won’t be submitted to any open source communities.

Each variable is explained with a comment.

// Default width of a flex item (when it is added or removed)let DEFAULT_ITEM_WIDTH  = '30px';
// Default height of a flex item (when it is added or removed)   let DEFAULT_ITEM_HEIGHT = '30px'; // Current X and Y mouse positionwindow.mx = 0;                      window.my = 0;
// When item is clicked,// we track its vertical and horizontal width:window.item_x = 0;                  window.item_y = 0;
// A flag to indicate whether an item is// currently being resized (or not)window.dragging = false;
// Mouse XY screen position at the time when last item was clickedwindow.drag_x = 0;                  window.drag_y = 0;
// The actual JavaScript element object of the item being draggedwindow.dragging_target = null;
// The ID of the item being clicked on and resizedwindow.dragging_id = -1;
// Item width and height, at the time it was clicked onwindow.item_width = 0;window.item_height = 0;
// The difference between current XY mouse position// and XY mouse position as its being draggedwindow.drag_width = 0;              window.drag_height = 0;
// Clicked item's "data-id" attributewindow.item_id = 0;
// For making a copy of the instance of// the flex object (for updating its HTML when// item number or size changes)window.flex = null;
// The 7 flex objects representing an instance of the flex classwindow.flex1 = null;              window.flex2 = null;window.flex3 = null;window.flex4 = null;window.flex5 = null;window.flex6 = null;window.flex7 = null;
// Don't know what this is :-) It's unused. But I hate to delete it.window.funcs = [];

Speaking of Software Architecture

Whenever you design an app, you will be thinking of its structure. That’s what Software Architecture is. It is the structure of your application.

As a software engineer, your task is to create the most efficient structure for your code. Efficient in this case means that it’s easy to modify in the long run without having to rewrite a lot of code all over again.

This means you should shoot for code reuse as much as possible when designing your application architecture.

Designing software means you will be working with component-based structures. One nested within another. But this flex application example is so simple, that we only have one class. The only class is our entire architecture.

Real-world application, of course, will be much more extensive than this. As far as this case, there really isn’t much architecture here.

The first thing you want to do is create a JavaScript class representing the main purpose of your application. Name it elegantly. In this case, I chose simply class flex.

Sure, this works. After all, we will be instantiating objects from this class that provides a flex container.

class flex {
constructor(_target,                id,                width,                height,                items,                item_width,                item_height,                justify_content) {
// I noticed that when justify-content is set to stretch,        // and item width is less than 100% of container width (or        // generally, something small, like 100px) then the stretch        // effect will not even take place. It'll just look like        // flex-start. So the purpose of this line of code is to set        // all item widths (by default) to 800px, (the full size of        // flex container.) This evenly spaces out all items in the        // container.
if (justify_content == 'stretch')            item_width = '800';
// Memorize the name of the HTML element's ID attribute        // (without leading '#' character)
this.tag                = _target;        this.variable_name      = _target;
// Grab the actual JavaScript object of the HTML container        this.target             = document.getElementById(_target);
// Flex container dimensions        this.width              = width;        this.height             = height;
// Number of items        this.items              = items;
// Create arrays holding width and height of items and        // populate them with defaults        this.items_widths  = new Array(items).fill(item_width);        this.items_heights = new Array(items).fill(item_height);
// Default width and height of the item        this.item_width         = item_width;        this.item_height        = item_height;
// Set justify-content property        this.justify_content    = justify_content;
// Is there an item being dragged/resized right now?        this.dragging           = false;
// Bind methods (if you don't do this they won't work)        this.setjustifycontent  = this.setjustifycontent;        this.source             = this.source;
// Render entire flex HTML into the container (to dynamically        // update it)        this.paste();    }
// ... class method functions follow ...    // (We will get to them shortly)

This is your class’s constructor. A constructor allows you to pass arguments to its parameter names. Constructors are usually used to initialize your object with a set of default values.

  • this.tag — When I create a new flex object, I want to remember the id attribute of its HTML parent container element.
  • this.variable_name — Same thing as above, it’s probably redundant but I made a copy just in case (don’t do this at home.)
  • this.target — The actual JavaScript object of the container HTML element.
  • this.width — The width of the container element.
  • this.height — The height of the container element.
  • this.items — The number of items in this flex container.
  • this.items_widths — 0-index array of widths of each item on the list.
  • this.items_heights — 0-index array of heights of each item on the list.
  • this.item_width — The default item width of all items.
  • this.item_height — The default item height of all items.
  • this.justify_content — value of justify-content for this flex container.
  • this.dragging — An item is being dragged right now (false by default.)
  • this.source — We need to bind the source class member function, otherwise our methods will not work outside of the class.
  • this.setjustifycontent — We need to bind the setjustifycontent class member function, otherwise it will not work.

And lastly let’s call the member function paste.

  • this.paste(); — all defaults are set, render the flex HTML container with items in it for the first time when the object is instantiated.

The constructor of flex class allows us to do the following:

// Initialize the 7 flex objects and assign them to window.flex[n]window.flex1 = new flex("flex1", "flex-a", 800, 40, 1, '200px', '30px', 'flex-start');window.flex2 = new flex("flex2", "flex-b", 800, 40, 2, '200px', '30px', 'flex-end');window.flex3 = new flex("flex3", "flex-c", 800, 40, 3, '50px', '30px', 'center');window.flex4 = new flex("flex4", "flex-d", 800, 40, 4, '50px', '30px', 'space-between');window.flex5 = new flex("flex5", "flex-e", 800, 40, 5, '50px', '30px', 'space-around');window.flex6 = new flex("flex6", "flex-f", 800, 40, 6, '50px', '30px', 'stretch');window.flex7 = new flex("flex7", "flex-g", 800, 40, 7, '50px', '30px', 'space-evenly');

The constructor instantiates each flex object separately using the JavaScript’s new keyword. We provide default values to it, so our flex object can crunch some data as a starting point during initialization.

Throughout the life cycle of the application, these values may change. (For example justify-content property will be changed via on-screen links displayed just above the flex container.)

Creating Class Method Functions

At this point we provided an instantiation mechanism for our flex class. As our primary (and the only) class, it will take a lot of parameters so we can set application defaults.

The application is still abstract at this time. We don’t have any functions that get anything done. And that’s the key behind designing your software using classes. They help define the structure of your application before writing code.

After constructor is completed, we’re ready to start working on our class’s member functions (also known as methods, in some languages.)

Method: flex.source() — create the CSS and HTML source code from class property names

The source method is what builds the source code for the flex layout associated with the flex object. It will take item number, the width of each individual item, and convert it to a string of text representing the HTML and CSS code to build the flex you designed using the flex layout designer.

Oh, and of course it will also take in consideration flex’s object justify-content property. This is what determines the unique default look of each flex block.

This method provides the code that is copied to the clipboard when the user clicks on Copy To Clipboard.

source() {
// Start with an empty string
let I = ``;
// Walk through each item on the list and        // create a content container for it:
for (let i = 0; i &lt; this.items; i++)            I += `    <div style = 'width: ` +                        this.items_widths[i] +                                `; height: ` +                        this.items_heghts[i] + `'>` + (i + 1) +                 `<;/div>\r\n`;
// Create the css style tag, put .flex class in it, create        // flex container and insert the list (we just created above)
        let src = `<style type = 'text/css'>\r\n    .flex { display: flex; flex-direction: row; justify-content: ` + this.justify_content + `; width: 800px; border: 1px solid gray; padding: 4px;}\r\n    .flex div { border: 1px solid gray; padding: 4px; background: #A4F2D8; font-family: Verdana; font-size: 19px; text-align: center; color: gray; }\r\n</style>\r\n<div class = 'flex'>\r\n` + I + `</div>`;
// Return the string we just constructed        return src;    }

We will simply call source method every time we need to copy the code to the browser’s (or operating system’s) built-in paste clipboard.

Method: flex.setjustifycontent() — set justify content value, and dynamically update flex HTML

Calling setjustifycontent member function will simply set a value to CSS justify-content property on that flex container. That’s what happens when you click one of those links on top of the flex container.

setjustifycontent(justify_content) {
// Set the property value    this.justify_content = justify_content;
// "Paste" the HTML into the flex container (update flex)    this.paste();}

That’s a pretty simple function, isn’t it? Next, let’s write the add function to add items to the list. Note, all of these functions go inside the object into the same scope where the constructor is. But later in this tutorial we will write some global helper functions.

add() {        // Memorize widths and heights of all items        let copyW = this.items_widths.slice();        let copyH = this.items_heights.slice();
// Reset all items widths and heights        // to their default values        this.items_widths[this.items] =            this.justify_content == 'stretch' ?                                    '800px' :                                    DEFAULT_ITEM_WIDTH;
this.items_heights[this.items] = DEFAULT_ITEM_HEIGHT;        this.items++;
// Set all items dimensions to values we memorized earlier
for (let i = 0; i < copyW.length; i++)            this.items_widths[i] = copyW[i];
for (let i = 0; i < copyH.length; i++)            this.items_heights[i] = copyH[i];
// Generate HTML and update view        this.paste();    }

The comments here are self-explanatory.

remove() { this.items--; this.paste(); }

Removing an item is as simple as decreasing the item’s counter. We are not actually deleting the item’s width / height arrays. This is important. We don’t want to delete the item dimensions, when the item is deleted. Because if the user decides to re-add it again, we want to preserve that item’s previous width and height. It just creates a better user experience.

Finally, the paste method (a bit awkwardly called so) is responsible for “pasting” the actual HTML code for the flex container and its items based on the current class parameters. This is the core behind updating the view of the application.

paste() {
// Start with an empty string
let list = ``;
// Walk through all existing items, and        // create item content container
for (let i = 0; i &lt; this.items; i++)            list += `&lt;div class = "item"                      id = "` + this.target + `_item_` + (i + 1) +                         `" data-id = "` + (i + 1) +              `" style = 'line-height: ` + this.items_heights[i] +                            `; height: ` + this.items_heights[i] +                             `; width: ` + this.items_widths[i] +                                            `'>` + (i + 1) +                                            `</div>`;
// Create the main container and insert the list        // we created in the above for-loop
let source = `<div class = 'justify_content_container'&gt;` + create_justify_content_modifier(this.tag, this.justify_content, this.variable_name) + `</div><div class = 'dynamic flex' style = 'width: ` + this.width + `; height: ` + this.height + `; justify-content: ` + this.justify_content + `'>` + list + `</div>`;
// Finally, paste the code into content of the HTML        // container element, effectively (and instantly) updating        // the browser view
this.target.innerHTML = source;
// The way event functions work does not allow us to        // reference "this" object, in the following "mousedown"        // callback function() {...here...}, so what we will do, is        // store a copy in "that" variable, and use it instead (that        // works.)
let that = this;
// An item inside this.target flex container was clicked!        $('.item', this.target).on("mousedown", function(e) {
// Assign the "that" object to global variable            // window.flex Using "this" here will not refer to flex            // class "this" but  the event's "this", which in this            // case would refer to the object that was clicked on,            // but that's not what we need. Instead, we store this            // flex class globally for future operations and access            // from our other helper functions            window.flex             = that;
// The item was clicked, so apply "editing" look to            // it (dashed border)            $(this).addClass("editing");
// Update the globals with useful info            window.dragging         = true;            window.drag_x           = e.pageX;            window.drag_y           = e.pageY;            window.dragging_target  = this;            window.item_id = parseInt($(this).attr('data-id')) - 1;
// Simply get initial width and height of an item we            // just clicked on we will use this to measure its new            // dimensions based on how far the mouse traveled from            // its original location after the item was clicked            // (window.drag_x and window.drag_y)            window.item_width  = parseInt($(this).css("width"));            window.item_height = parseInt($(this).css("height"));
// Store the width of the clicked item's            // width and height globally
if (this.target) window.item_x                    = parseInt($(this.target)[0].style.width);
if (this.target) window.item_y                    = parseInt($(this.target)[0].style.height);        });    }}

You see, every time we “paste” the new HTML based on the class’s current property values, we need to re-attach the onclick event to this newly inserted HTML. Otherwise your old event listener will be wiped out, and nothing will happen.

function copy_to_clipboard(target) {
// Get flex JavaScript object (window.flex1, for example        // if target = "flex1") and call the source method of the        // flex class we coded earlier        let src = window[target].source();
// Copy and paste can only be done from a textarea, grab        // its value and select it        document.getElementById('src').value = src;        document.getElementById('src').select();
// Execute the native "copy" command on text currently        // selected in the off-screen textarea        let copied = document.execCommand('copy');
// Flash container's border when "Copy To Clipboard" is        // clicked ...to let the user know the copy operation        // was a success        $("#" + target).animate({borderColor: '#00F'}, 200,            function() {                $("#" + target).animate({borderColor: '#EEE'}, 200);            });        }

Note you need an off-screen textarea to copy code from. This is why first, it is entered into the textarea, and selected. Only then the native OS “copy to clipboard” command is called to copy that selected text.

function setjustifycontent(object, target_id, command, value) {    $(".link", $(object).parent()).removeClass('sel');    $(object).addClass('sel');    window[target_id].setjustifycontent(value);}

This is self-explanatory too. We simply call setjustify content on target flex object. But this is a global function to accomplish that (not object’s member function.)

function create_justify_content_modifier(target_id, justify_content, object_variable_name) {    return `<p><b>justify-content</b>       <span class = "link` + (justify_content == 'flex-start' ? ' sel' : '') + `" onclick = "setjustifycontent(this, '` + target_id + `', '` + object_variable_name + `', 'flex-start')">flex-start</span>    <span class = "link` + (justify_content == 'flex-end' ? ' sel' : '') + `" onclick = "setjustifycontent(this, '` + target_id + `', '` + object_variable_name + `', 'flex-end')">flex-end</span>    <span class = "link` + (justify_content == 'center' ? ' sel' : '') + `" onclick = "setjustifycontent(this, '` + target_id + `', '` + object_variable_name + `', 'center')">center</span>    <span class = "link` + (justify_content == 'space-between' ? ' sel' : '') + `" onclick = "this, setjustifycontent(this, '` + target_id + `', '` + object_variable_name + `', 'space-between')">space-between</span>    <span class = "link` + (justify_content == 'space-around' ? ' sel' : '') + `" onclick = "setjustifycontent(this, '` + target_id + `', '` + object_variable_name + `', 'space-around')">space-around</span>    &lt;span class = "link` + (justify_content == 'stretch' ? ' sel' : '') + `" onclick = "setjustifycontent(this, '` + target_id + `', '` + object_variable_name + `', 'stretch')">stretch</span>    <span class = "link` + (justify_content == 'space-evenly' ? ' sel' : '') + `" onclick = "setjustifycontent(this, '` + target_id + `', '` + object_variable_name + `', 'space-evenly')">space-evenly</span></p>`;}

We’re almost done. But we need to add a few other things.

The next 3 blocks of code are connected by the same scope within the document ready function.

// All DOM items finished loading$(document).ready(function() {
// Initialize the 7 flexes    window.flex1 = new flex("flex1", "flex-a",        800, 40, 1, '200px', '30px', 'flex-start');
window.flex2 = new flex("flex2", "flex-b",        800, 40, 2, '200px', '30px', 'flex-end');
window.flex3 = new flex("flex3", "flex-c",        800, 40, 3, '50px', '30px', 'center');
window.flex4 = new flex("flex4", "flex-d",        800, 40, 4, '50px', '30px', 'space-between');
window.flex5 = new flex("flex5", "flex-e",        800, 40, 5, '50px', '30px', 'space-around');
window.flex6 = new flex("flex6", "flex-f",        800, 40, 6, '50px', '30px', 'stretch');
window.flex7 = new flex("flex7", "flex-g",        800, 40, 7, '50px', '30px', 'space-evenly');

In our main JavaScript program scope, first we initialize all of the flex objects, one after another.

$("body").on("mouseup", function() {
// Item finished resizing, disable dragging        window.dragging = false;
// Remove dashed border around the item        $(".item").removeClass("editing");
// Update width/height array with new item dimensions        if (window.flex) {             if (window.flex.items_widths &&                window.flex.items_widths[window.item_id])                window.flex.items_widths[window.item_id]                = window.drag_width + 'px';
if (window.flex.items_heights &&                window.flex.items_heights[window.item_id])                    window.flex.items_heights[window.item_id] =                    window.drag_height + 'px';        }    });

This is the global mouse “up” event. Basically, regardless of what’s happening, every time the mouse button is depressed (does anyone have any lithium?), we want to reset the dragging state to false. So our other code (see below) doesn’t kick in and continue to change the item’s size.

// Process mouse move event while dragging the item, update// its dimensions and line-height    $("body").mousemove(function(e) {
window.mx = e.pageX;        window.my = e.pageY;
if (window.dragging) {
// Calculate drag distance difference            let diffX =    window.drag_width =parseInt((window.item_width + (window.mx - window.drag_x) * 1.75));
let diffY =   window.drag_height =parseInt((window.item_height + (window.my - window.drag_y) * 1.75));
// Absolute values ensure the item dimensions            // never become negative            $(window.dragging_target).css("width",                Math.abs(diffX) + 'px');
$(window.dragging_target).css("height",                Math.abs(diffY) + 'px');
$(window.dragging_target).css("lineHeight",                Math.abs(diffY) + 'px');
// Change cursor to either left-right or up-down arrow,            // based on which direction the drag is the greatest
if (diffX > diffY) {                /* Optional, maybe a future feature... */            }        }    })});

And finally… the window.onload event makes sure all HTML elements and media (images, etc) have finished downloading from the server. Here, I used jQuery animation to animate the first flex item in the very first flex container, 500 milliseconds after the DOM and images have been loaded into the browser, to let the visitor know that this is an interactive flex designer, and they should click on items to resize them.

window.onload = () => {    setTimeout(function() {        $("#flex1 .item").addClass("editing");        $("#flex1 .item").animate( { width: "+=75px" }, 700);        $("#animcursor").animate( { left: "+=75px" }, 700, function() {            $("#flex1 .item").removeClass("editing");            $("#animcursor").animate( { opacity: 0 }, 400, function() {                $("#animcursor").remove();                let B = true;                let C = 0;                let T = setInterval( function() {                    if (B) { $('#flex1 .item').addClass("editing"); } else { $('#flex1 .item').removeClass("editing"); }                    B = !B;                    if (C++ > 6) { clearInterval(T); T = null; }                }, 60);            });        });    }, 500);}

Congratulations!

You have just created a flex layout designer in vanilla JavaScript.

Limited Time Offer

The diagrams in this tutorial were influenced directly by the manuscript!

CSS Visual Dictionary 28% OFF for Medium readers.

28% OFF

Grab Your Copy!

CSS Visual Dictionary

Contains all CSS properties