Skip to main content
4 of 12
added 18 characters in body

Review

I agree with the answer by CertainPerformance: the code does look pretty good. Indentation seems consistent, variable names are appropriate and lines are terminated well. Readability is great.

Excess CSS rules

The style font-size: 20px; should not be needed under .panel since the same rule is also specified on html, plus it gets overridden by more specific selectors.

Suggestion

Event delegation

Instead of adding event listeners to each panel element, event listeners can be added to the container element. This would require changing the event handlers to look at the event target and determining if the target matched a panel or child of a panel - can be done with the .closest() method. And a live HTMLCollection of elements with class name open can be fetched once using document.getElementsByClassName('open');. Then if any elements have that class when the click handler is called the class name can be removed.

This would allow adding and removing panels without needing to register the event handlers on them. While it may not make a noticable difference on a small page like this, it is wise to consider places where a loop can be avoided.

In the code snippet below, the only loop over the panels is in the transitioned event handler.

const panelsContainer = document.querySelector('.panels');
const openPanels = document.getElementsByClassName('open');

panelsContainer.addEventListener('click', e => {
  const panel = e.target.closest('.panel');
  if (!panel) {
    return;
  }
  const add = !panel.classList.contains('open');
  if (openPanels.length) {
    openPanels[0].classList.remove('open');
  }
  if (add) {
    panel.classList.add('open');
  }
});
panelsContainer.addEventListener('transitionend', e => {
  /* Safari transitionend event.propertyName === flex */
  /* Chrome + FF transitionend event.propertyName === flex-grow */
  if (e.propertyName === 'flex' || e.propertyName === 'flex-grow') {
    panelsContainer.childNodes.forEach(child => {
      if (child.nodeName.toLowerCase() !== 'div') {
        return;
      }
      const { classList } = child;
      classList.toggle('open-active', classList.contains('open'));
    });
  }
})
/*[...panelsContainer.childNodes].forEach(panel =>     
 panel.addEventListener('transitionend', e => {
  if(e.propertyName.includes('flex')) {
    panels.forEach(panel => {
      if(panel.classList.contains('open')) {
        panel.classList.add('open-active');
      } else {
        panel.classList.remove('open-active');
      }
    });
  }
}));*/
html {
  box-sizing: border-box;
  background: #ffc600;
  font-family: 'helvetica neue';
  font-size: 20px;
  font-weight: 200;
}

body {
  margin: 0;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}

.panels {
  min-height: 100vh;
  overflow: hidden;
  display: flex;
}

.panel {
  background: #6B0F9C;
  box-shadow: inset 0 0 0 5px rgba(255, 255, 255, 0.1);
  color: white;
  text-align: center;
  align-items: center;
  /* Safari transitionend event.propertyName === flex */
  /* Chrome + FF transitionend event.propertyName === flex-grow */
  transition: font-size 0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11), flex 0.7s cubic-bezier(0.61, -0.19, 0.7, -0.11), background 0.2s;
  
  background-size: cover;
  background-position: center;
  flex: 1;
  display: flex;
  justify-content: center;
  flex-direction: column;
}

.panel1 {
  background-image: url(https://source.unsplash.com/gYl-UtwNg_I/1500x1500);
}

.panel2 {
  background-image: url(https://source.unsplash.com/rFKUFzjPYiQ/1500x1500);
}

.panel3 {
  background-image: url(https://images.unsplash.com/photo-1465188162913-8fb5709d6d57?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&w=1500&h=1500&fit=crop&s=967e8a713a4e395260793fc8c802901d);
}

.panel4 {
  background-image: url(https://source.unsplash.com/ITjiVXcwVng/1500x1500);
}

.panel5 {
  background-image: url(https://source.unsplash.com/3MNzGlQM7qs/1500x1500);
}


/* Flex Children */

.panel>* {
  margin: 0;
  width: 100%;
  transition: transform 0.5s;
  flex: 1 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
}

.panel *:first-child {
  transform: translateY(-100%);
}

.panel *:last-child {
  transform: translateY(100%);
}

.panel.open-active *:first-child,
.panel.open-active *:last-child {
  transform: translateY(0);
}

.panel p {
  text-transform: uppercase;
  font-family: 'Amatic SC', cursive;
  text-shadow: 0 0 4px rgba(0, 0, 0, 0.72), 0 0 14px rgba(0, 0, 0, 0.45);
  font-size: 2em;
}

.panel p:nth-child(2) {
  font-size: 4em;
}

.panel.open {
  font-size: 40px;
  flex: 5;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Flex Panels 💪</title>
  <link href="https://fonts.googleapis.com/css?family=Amatic+SC" rel="stylesheet" type="text/css">
</head>

<body>

  <div class="panels">
    <div class="panel panel1">
      <p>Hey</p>
      <p>Let's</p>
      <p>Dance</p>
    </div>
    <div class="panel panel2">
      <p>Give</p>
      <p>Take</p>
      <p>Receive</p>
    </div>
    <div class="panel panel3">
      <p>Experience</p>
      <p>It</p>
      <p>Today</p>
    </div>
    <div class="panel panel4">
      <p>Give</p>
      <p>All</p>
      <p>You can</p>
    </div>
    <div class="panel panel5">
      <p>Life</p>
      <p>In</p>
      <p>Motion</p>
    </div>
  </div>

</body>

</html>