0

Context

I am making an image gallery slider (horizontal slider). I have a wrapper div .wrap set to 100% width and height of the window. I have another child div .image_wrap that wraps an <img>. It's dimensions are responsive so that that it's width and height vary depending on the orientation of the viewport; landscape or portrait. These dimensions are determined using media queries. The image is also responsive so that it's height or width is 100% of .image_wrap. If the viewport is landscape, then .image_wrap will have it's height set to 90vh and it's width will remain auto. If the viewport is portrait, then the situation is reversed. Now, I need the auto values set on both .image_wrap and <img> because I want to always maintain the aspect ratio of each image, as they can vary in size and orientation.

Problem

As for the div .description, I want it's width to always be the same as .image_wrap. Since, at times, .image_wrap will have a width of auto, the inner text of <p> will cause .description width to increase, thus causing .image_wrap width to increase beyond the width of <img>. Normally, the text is brief and this is not a problem as you can see in the first example image below. But when the text gets longer, my problem arises, as you can see in the second example image below. I have my CSS set up with width at 100% for the appropriate selectors. .bg is just a background div with an opacity to darken and add semi-transparency for .description.

What I've tried

Since I am using the flexbox model for my styling, I have tried various approaches:

  • flex-grow:1; on .description. But that affects height not width.

  • I even tried removing the flex properties on .description and using traditional methods for it's children. But I still get a larger width on .image_wrap than <img>.

  • I started thinking that because I am creating all elements dynamically in Javascript, that my browser is just loading the DOM first and then adding CSS rules. So I tried playing around with inline styles before and after the DOM loads the elements to see what happens. Either way the width of .image_wrap seems to never change on the current image. Note that the page is already loaded. The user triggers creation of the gallery with an onclick event.

My Markup

<html>
<body>
   <div class="wrap">
      <div class="image_wrap">
         <img src="myimage.jpg"  />

         <div class="description">
            <div class="bg"></div>
            <p>I am a description and I want to wrap when I am too long. I am a description and I want to wrap when I am too long.</p>
         </div>
      </div>
   </div>
</body>
</html>

My CSS

.wrap {
   display:flex;
   width:100%;
   height:100%;
   margin:0px;
   border:0px;
   padding:0px;
   justify-content:center;
   align-items:center;
}

.image_wrap {
   display:flex;
   width:auto;
   height:auto;
   max-width:90vw; 
   max-height:90vh; 
   margin:0px;
   border:0px;
   padding:0px;
   flex-direction:column;
}

img {
   width:auto;
   height:auto;
   margin:0px;
   border:0px;
   align-self:center;
}

.description {
   display:block;
   position:relative;
   width:100%;
   max-width:100%;
   height:auto;
   margin:-20vh 0px 0px 0px;
   border:0px;
   padding:0px;
   box-sizing:border-box;
   align-self:center;
}

.description .bg {
   display:block;
   position:absolute;
   left:0px;
   top:0px;
   width:100%;
   height:100%;
   margin:0px;
   border:0px;
   padding:0px;
   background-color:Black;
   opacity:0.5;
   z-index:0;
}

.description p {
   position:relative;
   width:100%;
   margin:0px;
   border:0px;
   padding:1em;
   color:White;
   font-size:2.5vh;
   text-align:center;
   box-sizing:border-box;
   flex-grow:1;
   z-index:1;
}

@media (orientation: landscape) {
   .image_wrap { height:90vh;}
   img { height:100%; }
}

@media (orientation: portrait) {
   .image_wrap { width:90vw; }
   img { width:100%; }
}

My Javascript

This is just some of the commands. The script is large and there are no inline styles, so I didn't see the need to show the rest. I can provide more of the script upon request.

image_wrap.appendChild(img) ;
image_wrap.appendChild(description) ;
description.appendChild(bg) ;
description.appendChild(p) ;
wrap.appendChild(image_wrap) ;

What I want

I want .description to have a width that is always the same as <img>. If the text is too long to fit into .image_wrap then it should wrap. Since .image_wrap sometimes has a width of auto, the inner text of <p> forces the width of .image_wrap to increase. I do not want that, but I need the width to be auto so that it's dimensions are the same as the image. Example images below. enter image description here enter image description here [![enter image description here][3]][3]

[3]:

.wrap {
   display:flex;
   width:100%;
   height:100%;
   margin:0px;
   border:0px;
   padding:0px;
   justify-content:center;
   align-items:center;
}

.image_wrap {
   display:flex;
   width:auto;
   height:auto;
   max-width:90vw; 
   max-height:90vh; 
   margin:0px;
   border:0px;
   padding:0px;
   flex-direction:column;
}

img {
   width:auto;
   height:auto;
   margin:0px;
   border:0px;
   align-self:center;
}

.description {
   display:block;
   position:relative;
   width:100%;
   max-width:100%;
   height:auto;
   margin:-20vh 0px 0px 0px;
   border:0px;
   padding:0px;
   box-sizing:border-box;
   align-self:center;
}

.description .bg {
   display:block;
   position:absolute;
   left:0px;
   top:0px;
   width:100%;
   height:100%;
   margin:0px;
   border:0px;
   padding:0px;
   background-color:Black;
   opacity:0.5;
   z-index:0;
}

.description p {
   position:relative;
   width:100%;
   margin:0px;
   border:0px;
   padding:1em;
   color:White;
   font-size:2.5vh;
   text-align:center;
   box-sizing:border-box;
   flex-grow:1;
   z-index:1;
}

@media (orientation: landscape) {
   .image_wrap { height:90vh;}
   img { height:100%; }
}

@media (orientation: portrait) {
   .image_wrap { width:90vw; }
   img { width:100%; }
}
<html>
<head>
<link rel="stylesheet" type="text/css" href="styles.css"  />
</head>

<body>
   <div class="wrap">
      <div class="image_wrap">
         <img src="https://i.stack.imgur.com/SBpCq.jpg"  />

         <div class="description">
            <div class="bg"></div>
            <p>I am a description and I want to wrap when I am too long. I am a description and I want to wrap when I am too long.</p>
         </div>
      </div>
   </div>
</body>
</html>
Xavier
  • 109
  • 9
  • You can set p width to img width by using Javascript. – dnaz Oct 27 '19 at 21:57
  • add this to description `width: 0;min-width: 100%;` – Temani Afif Oct 27 '19 at 22:02
  • @dnaz Yes but then I need to use inline styles for that and that would break my responsiveness on `p`. – Xavier Oct 27 '19 at 22:02
  • Thanks guys. The duplicate question had the answer. I didn't see that question before in my searches. By setting the display of `.image_wrap` to `inline-block` and the width of `p` to `0`, plus a `min-width` to `100%`, it worked! – Xavier Oct 27 '19 at 22:12
  • the duplicate doesn't tell about a single rule that could be used nowdays ;) `.image_wrap {width:min-content;}` demo https://codepen.io/gc-nomade/pen/PoojvZy – G-Cyrillus Oct 27 '19 at 23:00
  • @G-Cyr I did not know that property could use that value. Is that an experimental value? – Xavier Nov 17 '19 at 19:52
  • @Xavier it is actually at draft state https://drafts.csswg.org/css-sizing/#valdef-width-min-content , it is used mainly with grid and minmax() to size rows or columns. to use with caution if you mind old browsers. – G-Cyrillus Nov 17 '19 at 22:21

0 Answers0