1

I have some text inside a <p> that is inside a <div>. I have a css image shape that floats to one side. I want the text in the two upper boxes to wrap to the shape but also align to the bottom of the div. The two lower boxes work fine because I do not need to vertically align the text within them. The problem is, the text can vary in length and so can the amount of lines, so I can not use a fixed height. Therefore absolute positioning will not work, plus the text will ignore my floating css image shape.

I have read dozens of questions and answers and all of them seem to use hacks. There is also one question that seems to ask the same as mine, but I can't find it anymore, besides there was only one answer which was javascript based. I tried using flexboxes with align-items:flex-end; but that doesn't work well with my floating shapes. I also tried using a table and vertical-align:bottom; but my text just breaks to another line and doesn't wrap to the shape.

A workaround I came up with is to use padding-top on the text, but not knowing the height of the text means the text does not always position it to the bottom of the div, especially if the length of text changes.

EDIT: I am totally open to any new ideas. This was just the best approach I could come up with. I even started toying around with the idea of using only one shape for all four boxes. But that seems a bigger challenge.

EDIT: I also updated the URL's so you can now run the code snippet.

EDIT: I have decided to go the Javascript route and am working on a solution. I am open to any ideas.

EDIT: What bothers me the most, is that every single idea I come up with requires an army of Javascript. The solution, in my opinion, should NOT require a nightmare. CSS should be able to solve this, but I can't seem to find a way without Javascript.

div, img, p  {
   margin:0px;
   border:0px;
   padding:0px;
}

#wrapper {
   display:block;
   position:absolute;
   left:0px;
   top:0px;
   width:100%;
   height:100%;
}

.box {
   display:block;
   position:absolute;
   width:50%;
   height:50%;
}

.box p { line-height:1.5em; padding:10px; }

/* The image shape is 300px x 300px. * /
/* I use 50vh because I want the shape size to always be half of the window height. */
/* This gives the illusion of one larger shape. */
.shape {
   position:relative;
   shape-margin:2em;
   width:50vh;
   height:50vh;
}

/* My workaround solution - #top_left p, #top_right p { padding-top:29vh; } */
#top_left { right:50%; top:0%; }
#bottom_left { right:50%; top:50%; }
#top_right { left:50%; top:0%; }
#bottom_right { left:50%; top:50%; }

#top_left p, #bottom_left p { text-align:right; }
#top_right p, #bottom_right p { text-align:left; }

#top_left .shape { float:right; shape-outside:url('https://i.stack.imgur.com/B1Dzu.png'); }
#bottom_left .shape { float:right; shape-outside:url('https://i.stack.imgur.com/Vxmz0.png'); }
#top_right .shape { float:left; shape-outside:url('https://i.stack.imgur.com/UL8uT.png'); }
#bottom_right .shape { float:left; shape-outside:url('https://i.stack.imgur.com/EGBRz.png'); }
<div id="wrapper">
   <div id="top_left" class="box">
      <img src="https://i.stack.imgur.com/B1Dzu.png" class="shape"  />
      <p>Here is some text. Here is some text. Here is some text.</p>
   </div>

   <div id="top_right" class="box">
      <img src="https://i.stack.imgur.com/UL8uT.png" class="shape"  />
      <p>Here is some text. Here is some text. Here is some text.</p>
   </div>

   <div id="bottom_left" class="box">
      <img src="https://i.stack.imgur.com/Vxmz0.png" class="shape"  />
      <p>Here is some text. Here is some text. Here is some text.</p>
   </div>

   <div id="bottom_right" class="box">
      <img src="https://i.stack.imgur.com/EGBRz.png" class="shape"  />
      <p>Here is some text. Here is some text. Here is some text.</p>
   </div>
</div>

I have created an image to illustrate. The pink borders are just to show the box boundaries. enter image description here shape_top_left.png

shape_top_left.png

shape_top_right.png

shape_top_right.png

shape_bottom_left.png

shape_bottom_left.png

shape_bottom_right.png

shape_bottom_right.png

Xavier
  • 109
  • 9
  • 1
    this can probably help: https://stackoverflow.com/a/55278325/8620333 – Temani Afif Sep 13 '19 at 19:07
  • @Temani Afif I was able to get the two bottom boxes to work perfectly, which is almost identical to that question you linked. So no problems there. The big problem arises when I want to vertically align the text. – Xavier Sep 13 '19 at 19:11
  • can you edit your code to include the image of the shape? so basically you have issue with the top elements? – Temani Afif Sep 13 '19 at 19:13
  • @Temani Afif yes, just the top elements. And sorry about not adding the images. I will add them now. – Xavier Sep 13 '19 at 19:14
  • @Temani Afif images added. – Xavier Sep 13 '19 at 19:31
  • @Temani Afif I also updated the URL's so you can now run the code snippet. – Xavier Sep 13 '19 at 20:04
  • I am starting to feel like this layout design is unsolvable. In all my years of programming, nothing I have ever tried was unsolvable, nothing. – Xavier Sep 23 '19 at 16:22
  • I will try to check it again, if I am not able to find anything I post a bounty for you – Temani Afif Sep 23 '19 at 18:15
  • Even though I often end up solving my own questions here on SO, it doesn't stop me from asking them. Every time I learn something new, in fact a lot of things. That said, just posting the question itself gets me thinking of new ideas and solutions. – Xavier Sep 24 '19 at 05:36

2 Answers2

0

The best you will probably achieve is through using the shape-outside property

Check out here for some documentation.

However, be warned as of 2019 this isn't supported in Internet Explorer or Microsoft Edge

A simple enough codepen example would be this

jbutler483
  • 24,074
  • 9
  • 92
  • 145
  • That doc link takes you to the `shape-outside` property on MDN. Not sure what you meant by the `text-around` property. I have never heard of it and can't find any reference to it. That said, I am already using the `shape-outside` property, which is the primary basis for my layout design; and leads me to this question post. CSS shapes require a float on one side to work. – Xavier Sep 21 '19 at 01:20
0

Well here is my Javascript solution. It requires a lengthy script so I will just get to the core of the solution.

The Workaround

With my CSS image shape floating to the right I can still get wrapping text, even though I want my text to align to the bottom. Since no working spec I have seen allows me to vertically align my text to the bottom and get it to wrap to a CSS shape, I need to create the illusion with padding-top. I solved the dilemma of not knowing my text height by running a series of checks through a loop in Javascript. Just check the initial height of the text, then add a single increment of padding-top, then compare with the parent container's height. Repeat this process until the text height reaches or exceeds the parent containers height. The important thing here is that each time you add an increment of padding-top, you change the height of the text. The more padding you add, and the closer the text gets to the CSS shape, the more the text wraps and flows differently. This is why we need to check the height on each increment. Since my text has a font size in EM units, I would have a hard time knowing it's computed height doing guesswork. Add in client zooming and it's a math nightmare! Rather we just check with single increments and no math needed, hooray!

My Javascript

This is just a core example, not the full script, but you should get the idea.

var counter = 0 ;

function checkHeight()
{
var container = document.getElementById("top_left") ;
var text = document.getElementById("top_left_text") ;
var container_height = container.offsetHeight ;

counter++ ;
text.style.paddingTop = counter + "vh" ;
var text_height = text.offsetHeight ;
if ( text_height < container_height ) { checkHeight() ; }
}

Another Future Solution

Using CSS Exclusions.

With CSS Exclusions you can have an element that does not float but, behaves like a floating element, so that content wraps around the element in much the way that floating elements do. Unfortunately, there is almost no support for this technology at the moment. That said, I would strongly encourage anyone interested to join the discussion and get more buzz going for the draft to maybe become a real spec. CSS Exclusions open up some really cool possibilities that, in my opinion, bring HTML out of the stone age in terms of document flow.

In the case of my problem here, I would simply be able to absolutely position my CSS image shape and get my layout without the need of Javascript. My text would be vertically aligned to the bottom because there would be no floats to say otherwise.

For those who want to know more about CSS shapes, read this excellent article.

Xavier
  • 109
  • 9
  • If you are going to reuse the `counter` global variable, make sure to reset it when the loop is finished. – Xavier Sep 24 '19 at 05:53
  • After some adjustments, I feel it is better to use a while loop, instead of self calling a function. Eliminates the possibility of an infinite call stack. – Xavier Sep 24 '19 at 20:07