Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML position variable

Tags:

html

css

I know this is easy with Javascript but... is there any way with just CSS?

Let's say we have two elements (green and red) within a parent one (beige). The red element should be always to the right of the green one, except if the green one (because of the content) is too big to fit the parent in which case the red one will be over the green one (the normal behaviour would be the red element staying to the right of the green one and therefore being hidden because of the overflow of the parent)

In other words: red.x = min(green.x + green.w, beige.x+beige.w-red.w)

Example image

For more info, here's the concrete HTML:

<div class="beige" style="width:250px"> <!-- parent with a given width (unknown until the page is rendered) & overflow hidden -->
  <a class="green"> <!-- link with display:inline -->
    content
    <em class="red"></em> <!-- actually a button, 15 px width -->
  </a>
</div>

EDIT: @kyledws answer is awesome but I'll update the question with more info (needed things) such as:

  • red is only displayed when green:hover (that's why it's inside green)
  • you don't know beige width in CSS (in the real world beige is inside a with defined width but not known until the page is rendered)
  • green content is a variable length text, and the reason of red being pushed
  • if the green content does not fit into the parent, it should show the ellipsis (text-overflow: ellipsis; overflow: hidden)
  • must work in IE8+
like image 854
danikaze Avatar asked Jul 30 '14 00:07

danikaze


1 Answers

If you're able to wrap the content inside <a> in a span then try this.

HTML

<div class="beige">
    <a class="green" href="#">
      <span class="content">This is some text.</span><em class="red"></em>
    </a>
</div>

CSS

.beige {
  background-color: #EBDFA0;
  height: 32px;
  overflow: hidden;
  border: 4px solid #EBDFA0;
  white-space: nowrap;
  width: 400px;
}

.green {
  background-color: #4CA73D;
  color: #222;
  display: inline-block;
  height: 100%;
  text-decoration: underline;
  vertical-align: middle;
}

.content {
  display: inline-block;
  height: 100%;
  margin-left: 4px;
  position: relative;
  width: 100%;
  max-width: 364px;
  top: -50%;
}

.red {
  border: 2px solid red;
  display: inline-block;
  height: 28px;
  position: absolute;
  width: 28px;
}

Essentially the <a class="green">, <span class="content"> and <em class="red"> need to be display: inline-block and the <span class="content"> has to be width: 100% with a max-width of the different between the <div class="beige"> and the <em class="red" minus any additional padding/margin/border etc. (So in this example, max-width: 364px) By setting a width on the span you force the em outside of it's container but by setting a max-width you stop the em from flowing outside of the main wrapper.

Here is a codepen.io link to an example.

(Note: Most of the CSS above is just to make the example look like your images.)

UPDATE:

  1. To show or hide the <em class="red"> add the :hover pseudo-class to .beige and visibility or opacity to .red. (Use opacity if you want to use a transition.)

    .red {
      opacity: 0;
    }
    
    .beige:hover .red {
      opacity: 1;
    }
    
  2. Because the width of <div class="beige"> is unknown you can't use CSS to set max-width on <span class="content">.

    (The 100% in max-width: calc(100% - 28px) is width of <a class="green"> not <div class="beige">. I couldn't hack it with pseudo-elements, positioning, floats or different display types like flex either.)

    The way around this is to fix the max-width of the <span class="content"> in CSS (as is shown above) or use Javascript to detect the width of <div class="beige"> and then set the max-width.

    content.style.maxWidth = beige.clientWidth - red.clientWidth + "px";
    

I updated the example with visibility and Javascript versions.

Also, I added position: absolute to .red so <span class="content"> doesn't have empty space on the right.

like image 150
kyledws Avatar answered Nov 08 '22 04:11

kyledws