Responsive Relative Element Resizing + Responsive Text Overlay

Viewed 335

I ran into 2 problems while designing a image-based drop-down menu :

  1. No matter how long I try I can NOT get a flexed element within a container to remain the same height as the adjacent element. [If you look at my jsFiddle, each slideout content that is revealed by hover,should be the same height as the icons.]

  2. I can't get text over each image- I believe it is because the menu resizes itself based on devices width - which I cannot give up. All sources I've seen are based off of position:absolute, which I have not been able to get to work. [Specifically, there should be text on top of each image, labeling them.]

Comment for clarifications, if needed.

Here's the jsFiddle Thanks.

2 Answers

You would need to have the menu-top display as flex in order for its contents to stretch. For the overlay on the image the position: absolute rule is correct but it would need one of the positioning rules top right bottom left to be declared as well, and its parent to have relative position. I have created a flexbox-based snippet based on what you described. Note that I didn't use any columns, instead the children are wrapping on 50% and I use :nth-child(odd) to select the odd children and order: 1 or order: 2 rules accordingly to display the menu left or right. Also note that I used a .page__wrap class on a div to wrap the whole page, header, main and footer in order to flex them so the footer is always at the bottom even if there is no scrolling.

body {
  margin: 0;
}

.page__wrap {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

header {
  background-color: lightgray;
  border-bottom: 5px solid gray;
}

h2 {
  text-align: center;
  margin: 0;
  padding: 2em 0;
}

main {
  flex: 1;
}

footer {
  background-color: gold;
  padding: 1em 0;
  justify-self: flex-end;
}

.slideouts__wrapper {
  display: flex;
  flex-wrap: wrap;
  max-width: 65rem;
  margin: 0 auto;
}

.slideout {
  display: flex;
  margin: 10px;
  width: calc(50% - 20px);
  justify-content: flex-start;
}

.slideout:nth-child(odd) {
  justify-content: flex-end;
}

.slideout__avatar {
  background-color: red;
  flex: 0 1 auto;
  object-fit: cover;
  position: relative;
}

.slideout__avatar--image {
  display: block;
  width: 100%
}

.slideout__avatar--overlay {
  position: absolute;
  bottom: 0;
  width: 100%;
  background-color: #00000095;
  color: white;
  transition: .2s;
  display: flex;
  justify-content: center;
  align-items: center;
}

.slideout:nth-child(odd) .slideout__avatar {
  order: 2;
  position: relative;
}

.slideout__menu {
  display: flex;
  flex: 0 0 50%;
}

.slideout__menu--items {
  display: none;
  flex-direction: column;
  justify-content: stretch;
  margin: 0;
  padding:0;
  flex: 1;
  list-style: none;
  background-color: #736E6F;
  box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
  padding: 1%;
}

.slideout__menu--item {
  flex: 1;
  display: flex;
  border: thin inset #888585;
    border-radius: 5%;
}

.slideout__menu--item:hover {
  filter: brightness(1.2);
}

.slideout__menu--item--anchor {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  text-decoration: none;
    color: goldenrod;
}

.slideout__avatar:hover + .slideout__menu .slideout__menu--items {
  display: flex;
}

.slideout__avatar:hover .slideout__avatar--overlay {
  opacity: 1;
}

.slideout__menu--items:hover {
  display:flex;
}
<div class="page__wrap">
  <header>
    <div class="header__container">
      <h2>links of links</h2>
    </div>
  </header>
  <main class="slideouts__container">
    <div class="slideouts__wrapper">
      <div class="slideout">
        <div class="slideout__avatar">
          <img class="slideout__avatar--image" src="https://avatarfiles.alphacoders.com/105/thumb-105223.jpg" alt="scale">
          <div class="slideout__avatar--overlay">
            <p>the overlay</p>
          </div>
        </div>
        <div class="slideout__menu">
          <ul class="slideout__menu--items">
            <li class="slideout__menu--item"><a class="slideout__menu--item--anchor" href="#">link 1</a></li>
            <li class="slideout__menu--item"><a class="slideout__menu--item--anchor" href="#">link 2</a></li>
          </ul>
        </div>
      </div>
      <div class="slideout">
        <div class="slideout__avatar">
          <img class="slideout__avatar--image" src="https://avatarfiles.alphacoders.com/105/thumb-105223.jpg" alt="scale">
          <div class="slideout__avatar--overlay">
            <p>the overlay</p>
          </div>
        </div>
        <div class="slideout__menu">
          <ul class="slideout__menu--items">
            <li class="slideout__menu--item"><a class="slideout__menu--item--anchor" href="#">link 1</a></li>
            <li class="slideout__menu--item"><a class="slideout__menu--item--anchor" href="#">link 2</a></li>
            <li class="slideout__menu--item"><a class="slideout__menu--item--anchor" href="#">link 3</a></li>
          </ul>
        </div>
      </div>
      <div class="slideout">
        <div class="slideout__avatar">
          <img class="slideout__avatar--image" src="https://avatarfiles.alphacoders.com/105/thumb-105223.jpg" alt="scale">
          <div class="slideout__avatar--overlay">
            <p>the overlay</p>
          </div>
        </div>
        <div class="slideout__menu">
          <ul class="slideout__menu--items">
            <li class="slideout__menu--item"><a class="slideout__menu--item--anchor" href="#">link 1</a></li>
            <li class="slideout__menu--item"><a class="slideout__menu--item--anchor" href="#">link 2</a></li>
            <li class="slideout__menu--item"><a class="slideout__menu--item--anchor" href="#">link 3</a></li>
          </ul>
        </div>
      </div>
      <div class="slideout">
        <div class="slideout__avatar">
          <img class="slideout__avatar--image" src="https://avatarfiles.alphacoders.com/105/thumb-105223.jpg" alt="scale">
          <div class="slideout__avatar--overlay">
            <p>the overlay</p>
          </div>
        </div>
        <div class="slideout__menu">
          <ul class="slideout__menu--items">
            <li class="slideout__menu--item"><a class="slideout__menu--item--anchor" href="#">link 1</a></li>
            <li class="slideout__menu--item"><a class="slideout__menu--item--anchor" href="#">link 2</a></li>
            <li class="slideout__menu--item"><a class="slideout__menu--item--anchor" href="#">link 3</a></li>
            <li class="slideout__menu--item"><a class="slideout__menu--item--anchor" href="#">link 4</a></li>
          </ul>
        </div>
      </div>
      
    </div>
  </main>
  <footer>
    <div class="footer__container">
      <p>footer text</p>
    </div>
  </footer>
</div>

For clarity and code recycling the CSS has been split into four main sections:

  • Globals, page defaults and overrides of standard HTML/CSS values
  • Mechanism, Flexbox Layout settings and element sizing/actions
  • Eye-candy generics, spacing, fonts, borders
  • Eye-candy theming, anything color related using custom attribute [theme="gr-blue"]. Can be easily extended with other themes.

Flexbox Layout

For the left and right alignment of the .slideout-content you can simply use the row-reverse direction and justify-content: flex-end for an odd .menu-item and the default row direction for an even .menu-item

Image text overlay

Uses the standard position: relative and absolute parent/child element construction. The child content is filled with overlay text obtained from data-overlay custom attribute.

Remarks

  • The code is heavily commented and shows a few alternative uses for Flexbox Layout.
  • Removed filter: brightness(1.2) as IE11 cannot handle this, will need some alternative.
  • I have slightly changed the color opacity of .slideout-content to show some hover effects.
  • Where applicable I added viewport depended sizes.
  • Removed all uses of child margin and moved spacing to parent padding where applicable. This is especially important when using relative sizes ('%') combined with box-sizing: border-box, as margin increases the size of a child beyond 100%.
  • Don't use flex: 1 to allow elements to grow, use flex-grow: 1 instead for use with IE11.
  • Change dir="ltr" in <body> to dir="rtl" to test document reading order.

Tested to work with Chrome/Edge, Firefox and IE11 at a minimum size of 320x480px, without the need for scrolling.

UPDATE 1 I forgot to mention that I removed original footer {...height: 5vh...} which is not high enough for its content and will therefore overflow creating a white bar below the footer.

If you don't want a footer (or any parent element for that matter) to overflow, its height has to be at least greater/equal in height to its child(ren) (calculate line-height + padding + border + margin => whether to add padding + border depends on box-sizing).

UPDATE 2 To position overlay .slideout::after 3/4 from top and center in parent use: .slideout::after { top: 75%; left: 50%; transform: translate(-50%, -50%) }, I modified the CSS accordingly. Check out w3schools: CSS Layout - Horizontal & Vertical Align for more info on positioning.

SNIPPET

/***********/
/* GLOBALS */
/***********/
html,body           { width: 100%; max-width: 100%; height: 100% }

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

/* remove/override default element default */
html                { -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100% }
body                { margin: 0 }
ul,li               { list-style-type: none; padding: 0; margin: 0 }
a                   { text-decoration: none; color: inherit }
p                   { margin: 0; padding: 1em 0 }

/* for debugging (put in <body>) */
[outlines="1"] *    { outline: 1px dashed }

/*************/
/* MECHANISM */
/*************/

/******************/
/* Flexbox Layout */
/******************/

/* FBL EITHER (specific) */
/*.wrapper, .touch-menu, .menu-item,
.menu-item *                { display: flex }/**/

/* FBL OR (generic, if you want to insert elements on-the-fly without classes) */
div, ul, li, a, img         { display: flex }/**/

/* .wrapper is an FBL column of three main rows, pushed apart */
.wrapper                    { flex-direction: column; justify-content: space-between }

/* .touch-menu fills available space and is a row that wraps its kids */
.touch-menu                 { flex-grow: 1; flex-flow: row wrap }

/* 
   Because .menu-item width is 50% there will always be only two in a row,
   simply reverse FBL for first in a row...
*/
.menu-item:nth-child(odd)   { flex-direction: row-reverse } /* reverse row logic */
.menu-item:nth-child(odd)>* { justify-content: flex-end   } /* ditto */

.slideout-content           { flex-grow: 1 }           /* grow to fill parent */
.slideout-content ul        { flex-direction: column } /* a column of several rows */

.touch-menu,.slideout-content *, /* center all content rows/columns */
.header>*,.footer>*         { justify-content: center; align-content: center; align-items: center }
.footer>*                   { justify-content: flex-end } /* right align footer rows */

/**********/
/* Action */
/**********/
.slideout-content       { display: none } /* hide, change to 'flex' to verify positioning */

.slideout:hover+.slideout-content,
.slideout-content:hover { display: flex } /* show on hover */

/**********/
/* Sizing */
/**********/
.wrapper                { width: 100%; height: 100% }
.touch-menu             { padding: 0 5% }
/* modify 5% to required need, forces size of entire .menu-item */

.menu-item              { width: 50% } /* of .touch-menu */
.slideout               { width: 50%; position: relative } /* of .menu-item  */
.slideout::after        { position: absolute; bottom: 0; left: 0; right: 0 }

/* UPDATE 2 */
.slideout::after        { top: 75%; left: 50%; transform: translate(-50%, -50%) }


/* redundant, but > 50% will animate .slideout on hover */
.slideout-content       { width: 50% } /* otherwise: remove */

/* fill parent */
.header>*, .footer>*,
.slideout img           { width: 100% }
.slideout-content *     { width: 100%; height: 100% } /* modify to your needs */

/**********************/
/* EYE-CANDY generics */
/**********************/
.header                 { border-bottom-style: inset }
.header .headline       { padding: 0.67em 0; font-size: 2.6vw; font-weight: bold }
.touch-menu .menu-item  { padding: 1vh }

.slideout               { cursor: pointer }
.slideout::after        { content: attr(data-overlay); font-size: .75vw; padding: .25vw }

.slideout-content       { font-size: 1.5vw; padding: .25vw; box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2) }
.slideout-content ul *  { border-radius: 0.5vw } 
.slideout-content li    { padding: .125vw }
.slideout-content a     { border: thin inset }

.footer                 { padding: 2.65vmin .75vw; font-size: .75vw; border-top: outset }

/* ONLY required when 'FBL EITHER' used */
.header                 { text-align: center }
.footer                 { text-align: right  }

/*********************/
/* EYE-CANDY theming */
/*********************/
body { font-family: "Lato", sans-serif }

body[theme="gr-blue"] {
    color: GoldenRod; 
    /*
        Permalink - use to edit and share this gradient:
        https://colorzilla.com/gradient-editor/#c7d7dd+0,a7cfdf+16,5085a0+57,23538a+100
    */
    background-color: rgb(199,215,221); /* Old browsers */
    background-image:    -moz-linear-gradient(top, rgba(199,215,221,1) 0%, rgba(167,207,223,1) 16%, rgba(80,133,160,1) 57%, rgba(35,83,138,1) 100%); /* FF3.6-15 */
    background-image: -webkit-linear-gradient(top, rgba(199,215,221,1) 0%, rgba(167,207,223,1) 16%, rgba(80,133,160,1) 57%, rgba(35,83,138,1) 100%); /* Chrome10-25,Safari5.1-6 */
    background-image:   linear-gradient(to bottom, rgba(199,215,221,1) 0%, rgba(167,207,223,1) 16%, rgba(80,133,160,1) 57%, rgba(35,83,138,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */

    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#c7d7dd', endColorstr='#23538a',GradientType=0 ); /* IE6-9 */
}

[theme="gr-blue"] .header { color: AliceBlue; background-color: #605e5e; border-bottom-color: #888888 }
[theme="gr-blue"] .footer { background-color:#605e5e; border-color: GoldenRod }

[theme="gr-blue"] .slideout::after           { color: AliceBlue; background-color: rgba(115,110,111,.6) }
[theme="gr-blue"] .slideout-content          { background-color: rgba(115,110,111,.6) } /* #736e6f */
[theme="gr-blue"] .slideout-content a        { border-color: #888585 }
[theme="gr-blue"] .slideout-content li:hover { background-color: rgba(115,110,111,.6) }
<body theme="gr-blue" dir="ltr" outlines="0">
<div class="wrapper">
    <div class="header">
        <div class="headline">Links of Links</div>
    </div>

    <div class="touch-menu">
        <div class="menu-item">
            <div class="slideout" data-overlay="overlay 1">
                <img src="https://avatarfiles.alphacoders.com/105/thumb-105223.jpg" alt="scale">
            </div>
            <div class="slideout-content">
                <ul>
                    <li><a href="#">scaleLink 1</a></li>
                    <li><a href="#">scaleLink 2</a></li>
                    <li><a href="#">scaleLink 3</a></li>
                </ul>
            </div>
        </div>
        <div class="menu-item">
            <div class="slideout" data-overlay="overlay 2">
                <img src="https://avatarfiles.alphacoders.com/105/thumb-105223.jpg" alt="scale">
            </div>
            <div class="slideout-content">
                <ul>
                    <li><a href="#">bookLink 1</a></li>
                    <li><a href="#">bookLink 2</a></li>
                    <li><a href="#">bookLink 3</a></li>
                    <li><a href="#">bookLink 4</a></li>
                    <li><a href="#">bookLink 5</a></li>
                    <li><a href="#">bookLink 6</a></li>
                </ul>
            </div>
        </div>
        <div class="menu-item">
            <div class="slideout" data-overlay="overlay 3">
                <img src="https://avatarfiles.alphacoders.com/105/thumb-105223.jpg" alt="scale">
            </div>
            <div class="slideout-content">
                <ul>
                    <li><a href="#">ugavelLink 1</a></li>
                    <li><a href="#">ugavelLink 2</a></li>
                    <li><a href="#">ugavelLink 3</a></li>
                    <li><a href="#">ugavelLink 4</a></li>
                </ul>
            </div>
        </div>
        <div class="menu-item">
            <div class="slideout" data-overlay="overlay 4">
                <img src="https://avatarfiles.alphacoders.com/105/thumb-105223.jpg" alt="scale">
            </div>
            <div class="slideout-content">
                <ul>
                    <li><a href="#">lgavelLink 1</a></li>
                    <li><a href="#">lgavelLink 2</a></li>
                    <li><a href="#">lgavelLink 3</a></li>
                </ul>
            </div>
        </div>
    </div>

    <div class="footer">
        <div>
            Powered by <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=emb_logo" target="_blank">Barack Obama</a>
        </div>
    </div>
</div>
</body>

Related