Search code examples
javascriptcssmedia-queriesmatchmedia

Is there a smarter way to rearrange page elements than using matchMedia for this example?


I have created the following page layout, but it relies heavily on javascript. I've tried thinking of other ways to accomplish this more simply, but cannot come up with any.

Just wondering if anyone has any bright ideas to achieve this layout without javascript?

var hero = document.getElementById ('hero');
var aside = document.getElementById ('aside');
var main = document.getElementById ('main');

var smallMql = window.matchMedia('(max-width: 739px)');
var mediumMql = window.matchMedia('(min-width: 740px) and (max-width: 979px)');
var largeMql = window.matchMedia('(min-width: 980px)');

function drawSmallGrid(mql) {
  if (mql.matches) {
	  aside.setAttribute('style', 'margin-top: 0');
  }
}

function drawMediumGrid(mql) {
  if (mql.matches) {
  	var mainHeight = main.clientHeight;
	  aside.setAttribute('style', 'margin-top: -' + mainHeight + 'px');
  }
}

function drawLargeGrid (mql) {
  if (mql.matches) {
    var mainHeight = main.clientHeight;
    var heroHeight = hero.clientHeight;
    var totalHeight = mainHeight + heroHeight;

    aside.setAttribute('style', 'margin-top: -' + totalHeight + 'px');
  }
}

smallMql.addListener(drawSmallGrid);
mediumMql.addListener(drawMediumGrid);
largeMql.addListener(drawLargeGrid);

drawSmallGrid(smallMql);
drawMediumGrid(mediumMql);
drawLargeGrid(largeMql);
/**
 * Grid
*/

.hero,
.main {
	box-sizing: border-box;
}

/* Content faking */
.hero .module {background:aqua;}
.main .module {background:red;}
.aside .module {background:orange}

.hero .module,
.main .module {
	min-height: 200px;
}

.aside .module {
	min-height: 400px;
}

/* Grid layout */
.hero,
.main,
.aside {
	padding-left: 15px;
	padding-right: 15px;
}

@media (min-width: 740px) {
  .main {
    margin-right: 330px;
    max-width: 70%;
  }
  
  .aside {
    width: 300px;
    float: right;
  }
}
<div id="hero" class="hero"><div class="module">hero</div></div>
<div id="main" class="main"><div class="module">main</div></div>
<div id="aside" class="aside"><div class="module">aside</div></div>


Solution

  • I investigated flexbox but it was too complicated for my layout, as well as IE10+. I actually remembered the css calc value, which is IE9+, and it works a treat, with no javascript at all:

    /**
    * Grid
    */
    
    .hero,
    .main {
      box-sizing: border-box;
    }
    
    /* Content faking */
    .module { padding: 10px; }
    .hero .module { background: aqua; }
    .main .module { background: red; }
    .aside .module { background: orange; }
    
    .hero .module,
    .main .module {
      min-height: 200px;
    }
    
    .aside .module {
      min-height: 400px;
    }
    
    @media (min-width: 740px) {
      .module:after {
        display: inline;
        content: ' 740px+';
        font-style: italic;
      }
      
      .main {
        float: left;
        width: calc(100% - 330px);
      }
      
      .aside {
        float: right;
        width: 300px;
      }
    }
    
    @media (min-width: 980px) {
      .module:after {
        display: inline;
        content: ' 980px+';
        font-style: italic;
      }
      
      .container {
        width: calc(100% - 330px);
        float: left;
      }
      
      .main {
        float: none;
        width: 100%;
      }
    }
    <div class="container">
      <div id="hero" class="hero"><div class="module">hero</div></div>
      <div id="main" class="main"><div class="module">main</div></div>
    </div>
    <div id="aside" class="aside"><div class="module">aside</div></div>