📜 ⬆️ ⬇️

Vertical centering of simple divs with data-

Good day.

There was a problem : in twitter bootstrap there are two columns (div) with the classes "col-md-6" and "col-md-6". In the first column is the text, in the second video with YouTube, with the first column twice the second. It is necessary to center the video vertically relative to the first column. And there are several such sites on the site. In some places you need to make equal heights for two columns.

It would be possible to rule with my hands every time, but I decided to try to speed everything up, write a script that, by adding data, would do the routine work for me.

Denote the attributes that we need:
')

Variant chose three possible actions:

  1. height - Align the column height.
  2. margin - Aligns the div child elements in the middle of the screen (using the margin-top on the first child element).
  3. margin height - Aligns the children in the middle (using the margin-top on the first child), and lower the lower border of the smaller column to the value of the larger column (using the margin-bottom on the last child).

Decided what actions we need. Then add the conditions:

  1. When changing the width of the user's screen, recalculate the dimensions in the script (if the user is not playing with the browser width, the recalculation will be performed once, when the page loads)
  2. There is a browser width, while reducing the width of the browser window less than this value, the columns will be located one under the other. Here we do not need centering or height calculation.

Determine the variables:

var allowedWidthOfTheWindow = 992; //  ,        var elemsToCompare = [], // DOM    [[a,b,c],[a,b,c]] dataForCompareHeight = {}; //    (  localArrayForStaticElems) var localArrayForStaticElems = []; //       () var correctingHeights = false; //    allowedWidthOfTheWindow,     /   var userScreenWidth, userScreenHeight; //     

Get an array with all the divs using the data-compareheight attribute :

 var elemsWithOurDataset = document.querySelectorAll("div[data-compareheight]"); 

From the resulting array of DOM elements, you need to extract elements with the same data-compareheight attributes . And also discard elements that are not a pair.

 //      var i = 0; while(true){ if (elemsWithOurDataset.length <= 1) break; //       2 ,      if(!dataForCompareHeight[elemsWithOurDataset[i].dataset.compareheight]) { dataForCompareHeight[elemsWithOurDataset[i].dataset.compareheight] = ""; localArrayForStaticElems.push(elemsWithOurDataset[i].dataset.compareheight);}; dataForCompareHeight[elemsWithOurDataset[i].dataset.compareheight] += i + " "; i++; if (i == elemsWithOurDataset.length) break; //     DOM  } 

After the code above, we get an array with arrays consisting of element numbers with a common data-compareheight . In other words, at the moment we have:
[[a, b, c], [d, e]] (where a, b, c, d, e are element numbers, with elements a , b , c and d , e elements having the same data-compareheight ) .

We need to convert the resulting array from the element numbers to an array of DOM elements with which we will work:

 //    DOM  for (var i = 0; i < localArrayForStaticElems.length; i++){ var numberOfElems = dataForCompareHeight[localArrayForStaticElems[i]].split(" "); numberOfElems.pop(); if (numberOfElems.length < 2) continue; var localArr = []; for (var j = 0; j < numberOfElems.length; j++){ localArr.push(elemsWithOurDataset[numberOfElems[j]]); } elemsToCompare.push(localArr); } 

Now we have a filled array with DOM elements (and not element numbers). A permanent part (assuming no addition of elements and not reloading the page ) is received. We will continue to work with sizes and styles.

It is also worth calculating the width of the scroll bar (if any), since it reduces the apparent width of the client window and the column transfer occurs at a lower value than expected.

 //        ()      function setBreakePointWidthMinusScrollWidth(){ allowedWidthOfTheWindow = allowedWidthOfTheWindow - window.innerWidth + document.body.clientWidth; } 

Let's write a function to determine the height and width of the user's screen:

 function checkUserScreenSize(){ userScreenWidth = document.documentElement.clientWidth; userScreenHeight = document.documentElement.clientHeight; } 

Now we will write a function to find the maximum value in the array. This can be done by simple sorting (but you need to take into account that usually sorting .sort () goes just like for strings, let's write an additional function for sorting by numbers):

 //     ,  -  //       function checkTheLargestElement(){ for (var i = 0; i < elemsToCompare.length; i++){ elemsToCompare[i].sort(compareNumericArray); } } //      numberic  function compareNumericArray(a, b) { return b.clientHeight + getComputedStyle(b).marginTop + getComputedStyle(b).marginBottom - a.clientHeight - getComputedStyle(a).marginTop - getComputedStyle(a).marginBottom; } 

Let's write a function to determine if the width of the user's browser has exceeded the value at which the columns line up under each other.

 //          -  function checkAllowedMovingOrNot(){ if (userScreenWidth < allowedWidthOfTheWindow){ if (!correctingHeights) return; correctingHeights = false; } else{ correctingHeights = true; } } 

In the function above, depending on the size of the screen (or rather, the width), we obtain true / false, which can be used in the calculation of indents.

It's time to write a function that determines what to do depending on the second data-compareheightdo attribute :

 function checkParams(elem){ if (elem.getAttribute("data-compareheightdo")){ var a = elem.getAttribute("data-compareheightdo").toLowerCase(); if (a == "margin"){ return 1; } if (a == "height"){ return 2; } if ((a == "margin height") || (a == "height margin")){ return 3; } } return 0; } 

If the function returns 0, then either the data-compareheightdo attribute is not specified, or it is specified incorrectly.

Go to the size. Calculate the height of all child elements within the DIV (without going into the child elements of the child elements, that is, restrict ourselves to parent.children [i]). For the first child element we will not take into account the margin-top. This value will be used for vertical centering and automatically set depending on other parameters.

 //       margin-top   function getTotalHeightOfChildren(parent){ var heightNow = 0; for (var i = 0; i < parent.children.length; i++){ if(i == 0){ heightNow += parent.children[i].offsetHeight + parseInt(getComputedStyle(parent.children[i]).marginBottom); continue; } if(i == (parent.children.length - 1)){ heightNow += parent.children[i].offsetHeight + parseInt(getComputedStyle(parent.children[i]).marginTop); continue; } heightNow += parent.children[i].offsetHeight + parseInt(getComputedStyle(parent.children[i]).marginTop + getComputedStyle(parent.children[i]).marginBottom); } return heightNow; } 

Now we have all the helper functions for writing the indent function.

 //     margin-top (,  ) //   height function makeElementsEqualHeight(){ if(correctingHeights){ //           for(var i = 0; i < elemsToCompare.length; i++){ for (var j = 1; j < elemsToCompare[i].length; j++){ if (checkParams(elemsToCompare[i][j]) == 0) continue; if(checkParams(elemsToCompare[i][j]) == 1){ elemsToCompare[i][j].children[0].style.marginTop = parseInt((elemsToCompare[i][0].offsetHeight - getTotalHeightOfChildren(elemsToCompare[i][j]))/2) + "px"; } if(checkParams(elemsToCompare[i][j]) == 2){ if(!elemsToCompare[i][j].querySelector("div[class='notchange']")){ //        notchange var div = document.createElement("div"); //    ,   div.classList.add("notchange"); //       DOM  elemsToCompare[i][j].appendChild(div); //       } elemsToCompare[i][j].lastChild.style.marginBottom = parseInt((elemsToCompare[i][0].offsetHeight - getTotalHeightOfChildren(elemsToCompare[i][j])) - 1) + "px"; } if(checkParams(elemsToCompare[i][j]) == 3){ if(!elemsToCompare[i][j].querySelector("div[class='notchange']")){ var div = document.createElement("div"); div.classList.add("notchange"); elemsToCompare[i][j].appendChild(div); } elemsToCompare[i][j].children[0].style.marginTop = parseInt((elemsToCompare[i][0].offsetHeight - getTotalHeightOfChildren(elemsToCompare[i][j]))/2) + "px"; elemsToCompare[i][j].lastChild.style.marginBottom = parseInt((elemsToCompare[i][0].offsetHeight - getTotalHeightOfChildren(elemsToCompare[i][j]))/2 - 1) + "px"; } } } } else{ //           for(var i = 0; i < elemsToCompare.length; i++){ for (var j = 1; j < elemsToCompare[i].length; j++){ if (checkParams == 0) continue; elemsToCompare[i][j].children[0].style.marginTop = ""; elemsToCompare[i][j].lastChild.style.marginBottom = ""; } } } } 

Pay attention to the moment with the addition of the child div element. This is done for the purpose of easy access to the last element and this element can be easily edited using javascript without interfering with the main code.

Also note that we subtract 1px so that there is a difference between the largest and child elements.

There are code sections where not elemsToCompare [i] [ j ] is used, but elemsToCompare [i] [ 0 ]. We previously wrote a function to sort the elements of an array. This means that the first value (with index 0) has the largest dimensions.

Depending on the data-compareheightdo attribute, we have values ​​of 0/1/2/3, depending on this, ignore / only indent from the top (centering) / Only alignment of the lower edge of the column at the lower edge of the largest value / Centering and alignment of the lower edge.

Let's write a function that combines all the functions together:

 //       function recountElems(){ checkUserScreenSize(); //     checkTheLargestElement(); //       (  data-compareheight="NAME") checkAllowedMovingOrNot(); // ,       makeElementsEqualHeight(); //  margin-top  margin-bottom   }; 

Calculate the values ​​when loading the page. If the person will not play with the browser window, these values ​​will not change:

 setBreakePointWidthMinusScrollWidth(); //          recountElems(); //    ,     

Add a handler that works when the user resizes the screen and reads the new values:

 //         window.onresize = function(e){ recountElems(); } 

Everything, we finished to develop a script, it is ready.

Complete code:

 //    var allowedWidthOfTheWindow = 992; //  ,        var elemsToCompare = [], // DOM    [[a,b,c],[a,b,c]] dataForCompareHeight = {}; //    (  localArrayForStaticElems) var localArrayForStaticElems = []; //       () var correctingHeights = false; //    allowedWidthOfTheWindow,  false var userScreenWidth, userScreenHeight; //     var elemsWithOurDataset = document.querySelectorAll("div[data-compareheight]"); //      var i = 0; while(true){ if (elemsWithOurDataset.length <= 1) break; if(!dataForCompareHeight[elemsWithOurDataset[i].dataset.compareheight]) { dataForCompareHeight[elemsWithOurDataset[i].dataset.compareheight] = ""; localArrayForStaticElems.push(elemsWithOurDataset[i].dataset.compareheight);}; dataForCompareHeight[elemsWithOurDataset[i].dataset.compareheight] += i + " "; i++; if (i == elemsWithOurDataset.length) break; } //    DOM  for (var i = 0; i < localArrayForStaticElems.length; i++){ var numberOfElems = dataForCompareHeight[localArrayForStaticElems[i]].split(" "); numberOfElems.pop(); if (numberOfElems.length < 2) continue; var localArr = []; for (var j = 0; j < numberOfElems.length; j++){ localArr.push(elemsWithOurDataset[numberOfElems[j]]); } elemsToCompare.push(localArr); } //    //       ()      function setBreakePointWidthMinusScrollWidth(){ allowedWidthOfTheWindow = allowedWidthOfTheWindow - window.innerWidth + document.body.clientWidth; } function checkUserScreenSize(){ userScreenWidth = document.documentElement.clientWidth; userScreenHeight = document.documentElement.clientHeight; } //     ,  -  //       function checkTheLargestElement(){ for (var i = 0; i < elemsToCompare.length; i++){ elemsToCompare[i].sort(compareNumericArray); } } //      numberic  function compareNumericArray(a, b) { return b.clientHeight + getComputedStyle(b).marginTop + getComputedStyle(b).marginBottom - a.clientHeight - getComputedStyle(a).marginTop - getComputedStyle(a).marginBottom; } //       margin-top   function getTotalHeightOfChildren(parent){ var heightNow = 0; for (var i = 0; i < parent.children.length; i++){ if(i == 0){ heightNow += parent.children[i].offsetHeight + parseInt(getComputedStyle(parent.children[i]).marginBottom); continue; } if(i == (parent.children.length - 1)){ heightNow += parent.children[i].offsetHeight + parseInt(getComputedStyle(parent.children[i]).marginTop); continue; } heightNow += parent.children[i].offsetHeight + parseInt(getComputedStyle(parent.children[i]).marginTop + getComputedStyle(parent.children[i]).marginBottom); } return heightNow; } //     margin-top (,  ) //   height function makeElementsEqualHeight(){ if(correctingHeights){ //           for(var i = 0; i < elemsToCompare.length; i++){ for (var j = 1; j < elemsToCompare[i].length; j++){ if (checkParams(elemsToCompare[i][j]) == 0) continue; if(checkParams(elemsToCompare[i][j]) == 1){ elemsToCompare[i][j].children[0].style.marginTop = parseInt((elemsToCompare[i][0].offsetHeight - getTotalHeightOfChildren(elemsToCompare[i][j]))/2) + "px"; } if(checkParams(elemsToCompare[i][j]) == 2){ if(!elemsToCompare[i][j].querySelector("div[class='notchange']")){ //        notchange var div = document.createElement("div"); //    ,   div.classList.add("notchange"); //       DOM  elemsToCompare[i][j].appendChild(div); //       } elemsToCompare[i][j].lastChild.style.marginBottom = parseInt((elemsToCompare[i][0].offsetHeight - getTotalHeightOfChildren(elemsToCompare[i][j])) - 1) + "px"; } if(checkParams(elemsToCompare[i][j]) == 3){ if(!elemsToCompare[i][j].querySelector("div[class='notchange']")){ var div = document.createElement("div"); div.classList.add("notchange"); elemsToCompare[i][j].appendChild(div); } elemsToCompare[i][j].children[0].style.marginTop = parseInt((elemsToCompare[i][0].offsetHeight - getTotalHeightOfChildren(elemsToCompare[i][j]))/2) + "px"; elemsToCompare[i][j].lastChild.style.marginBottom = parseInt((elemsToCompare[i][0].offsetHeight - getTotalHeightOfChildren(elemsToCompare[i][j]))/2 - 1) + "px"; } } } } else{ //           for(var i = 0; i < elemsToCompare.length; i++){ for (var j = 1; j < elemsToCompare[i].length; j++){ if (checkParams == 0) continue; elemsToCompare[i][j].children[0].style.marginTop = ""; elemsToCompare[i][j].lastChild.style.marginBottom = ""; } } } } //          -  function checkAllowedMovingOrNot(){ if (userScreenWidth < allowedWidthOfTheWindow){ if (!correctingHeights) return; correctingHeights = false; } else{ correctingHeights = true; } } // ,         //  ,  : // height // margin function checkParams(elem){ if (elem.getAttribute("data-compareheightdo")){ var a = elem.getAttribute("data-compareheightdo").toLowerCase(); if (a == "margin"){ return 1; } if (a == "height"){ return 2; } if ((a == "margin height") || (a == "height margin")){ return 3; } } return 0; } //       function recountElems(){ checkUserScreenSize(); //     checkTheLargestElement(); //       (  data-compareheight="NAME") checkAllowedMovingOrNot(); // ,       makeElementsEqualHeight(); //  margin-top   }; setBreakePointWidthMinusScrollWidth(); //          recountElems(); //    ,     //         window.onresize = function(e){ recountElems(); } 

Let's check this code with a simple example. Use only vertical centering margin . Create two columns with a div, with the style float: left. Calculate the size of what we get.

 <head> <meta charset="UTF-8"> <style> .elem1{ width: 35%; border: 1px dashed #ccc; float: left; margin-left: 20px; } p{ padding: 0px; margin: 0px; } body{ padding: 0px; margin: 0px; } </style> </head> <body> <div class="parent"> <div class="elem1" data-compareheight="hello" data-compareheightdo="margin"><p>What is Lorem Ipsum? Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum</p></div> <div class="elem1" data-compareheight="hello" data-compareheightdo="margin"><p>What is Lorem Ipsum? Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's</p><p style="margin-top: 15px;">What is Lorem Ipsum? Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's</p></div> </div> <div style="clear: both"></div> <script src="compareHeight.js"></script> <!--    --> </body> 

Screen width 1100px. The height of the larger column is 198px. The height of the child elements of the smaller column is 54px (row height) + 54px (row height) + 15px (margin-top for the second P). In sum, we get the height of the child elements 123px.

To center vertically, you need to divide the difference by two and add a margin-top on top. (198px - 123px) / 2 = (75px) / 2 = 37.5px (required margin-top). In practice, we have 38px. That's right.

We also check the height by replacing data-compareheightdo = " margin " with data-compareheightdo = " height ".

The difference in 1px between the largest and smallest unit. (this 1px came from earlier when we read it in the function makeElementsEqualHeight .

Check another option when centering vertically and leveling the heights of the columns. Replace: data-compareheightdo = " margin " with data-compareheightdo = " margin height "

We get:


PS I got these values ​​in Chrome in the developer tools (F12 key).

PSS These methods work only with DIV elements (selector on div set).

Thanks for attention!

Source: https://habr.com/ru/post/325118/


All Articles