1

I'm trying to insert a bunch of elements that are out of the flow but vertically aligned to inline elements.

Here is the result I want to achieve (yes it's ugly but it hopefully helps diagram the issue).

enter image description here

The HTML starts with a bunch of <span>bigger</span> elements. To each <span> some HTML template for a red arrow (⬅) is inserted. I want that red arrow to vertically align to the middle of the <span>. The reason "bigger" has the 2 color background is to make it clear where the vertical middle is. The arrows need to vertically align with that middle.

Below is the code so far that doesn't work. To acheive my goal I can only change the CSS below the /* only change css below this line */ and the <template> HTML. The point being I can not hard code heights for each situation. The solution must be fluid.

PS: I don't care about the "and"s. I only care the arrows point to the middle of their corresponding "bigger"

/* do not change any JavaScript */

const template = document.querySelector('#arrow');
document.querySelectorAll('span').forEach(elem => {
  const child = template.content.cloneNode(true).children[0];
  elem.appendChild(child);
});
.f1 { font-size: 10pt; }
.f2 { font-size: 15pt; }
.f3 { font-size: 25pt; }
.f4 { font-size: 30pt; }
.f5 { font-size: 35pt; }
.f6 { font-size: 40pt; }
.f7 { font-size: 45pt; }
.f8 { font-size: 50pt; }
.f9 { font-size: 55pt; }
.f10 { font-size: 60pt; }
.f11 { font-size: 65pt; }
.f12 { font-size: 70pt; }

/* only change css below this line */

.f {
  background: linear-gradient(#e66465 50%, #9198e5 50%);
  display: inline-block;
  position: relative;
}

.arrow {
  position: absolute;
  right: 0;
  top: 0;
  display: inline-block;
}
.arrow>div:before {
  content: 'f';
  color: rgba(0,0,0,0);
}
.arrow>div {
  position: absolute;
  left: 0;
  top: 0;
}
.arrow>div>div {
  position: absolute;
  bottom: 0;
  color: rgba(255, 0, 0, 0.5);
  font-size: 20pt;
}
<p>
Alice drank the potion and she got 
<span class="f f1">bigger</span> and 
<span class="f f2">bigger</span> and 
<span class="f f3">bigger</span> and 
<span class="f f4">bigger</span> and 
<span class="f f5">bigger</span> and 
<span class="f f6">bigger</span> and 
<span class="f f7">bigger</span> and 
<span class="f f8">bigger</span> and 
<span class="f f9">bigger</span> and 
<span class="f f10">bigger</span> and 
<span class="f f11">bigger</span> and 
<span class="f f12">bigger</span> and 
</p>

<!-- only change html below this line -->

<template id="arrow">
  <div class="arrow">
    <div>
      <div>⬅</div>
    </div>
  </div>
</template>
gman
  • 100,619
  • 31
  • 269
  • 393
  • okay i misread the rules, so no html or javascript additions or change? and only add css not change anything? – Stanley Apr 11 '20 at 07:14
  • 1
    you can simply add `top: 50%; transform: translateY(-50%);` to .arrow>div>div and remove bottom:0 – Temani Afif Apr 11 '20 at 08:56
  • Not a single one of the "dupe" answer actually answers this question. All of those answers concerned with centering a box in a box, This one centering inline – gman Nov 19 '20 at 12:48

2 Answers2

1

here is my resultenter image description here

by adding another box that can be whatever, in this instance <a> I was able to create a flex box.

  const template = document.querySelector('#arrow');
document.querySelectorAll('span').forEach(elem => {
  const child = template.content.cloneNode(true).children[0];
  elem.appendChild(child);
});
.f1 { font-size: 10pt; }
.f2 { font-size: 15pt; }
.f3 { font-size: 25pt; }
.f4 { font-size: 30pt; }
.f5 { font-size: 35pt; }
.f6 { font-size: 40pt; }
.f7 { font-size: 45pt; }
.f8 { font-size: 50pt; }
.f9 { font-size: 55pt; }
.f10 { font-size: 60pt; }
.f11 { font-size: 65pt; }
.f12 { font-size: 70pt; }

/* only change css below this line */

.f {
  background: linear-gradient(#e66465 50%, #9198e5 50%);
  display: inline-block;
  position: relative;
}

.arrow {
  position: absolute;
  right: 0;
  top: 0;
  display: inline-block;
}
.arrow>div:before {
  content: 'f';
  color: rgba(0,0,0,0);
}
.arrow>div {
  position: absolute;
  left: 0;
  top: 0;
}
.arrow>div>div {
  position: absolute;
  bottom: 0;
  color: rgba(255, 0, 0, 0.5);
  font-size: 20pt;
}
 /*------------------Only added css bellow---------------------*/

.arrow div div{
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
<p>
Alice drank the potion and she got
<span class="f f1">bigger</span> and
<span class="f f2">bigger</span> and
<span class="f f3">bigger</span> and
<span class="f f4">bigger</span> and
<span class="f f5">bigger</span> and
<span class="f f6">bigger</span> and
<span class="f f7">bigger</span> and
<span class="f f8">bigger</span> and
<span class="f f9">bigger</span> and
<span class="f f10">bigger</span> and
<span class="f f11">bigger</span> and
<span class="f f12">bigger</span> and
</p>



<!-- only change html below this line -->

<template id="arrow">
  <div class="arrow">
    <div>
      <div><a>⬅</a></div>
    </div>
  </div>
</template>

The only css added

.arrow div div{
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
Stanley
  • 2,434
  • 18
  • 28
0

I'd skip the javascript and .arrow elements and use CSS pseudo elements.

.f::after {
  content: "⬅";
  color: rgba(255, 0, 0, 0.5);
  font-size: 20pt;

  position: absolute;
  display: inline-block;
  right: -22pt;
  top: 50%;
  transform: translateY(-50%);
}

I'm using position absolute to make sure document flow isn't affected. I pull the element right to not overlap, then use top: 50%; transform: translateY(-50%) to vertically center it (the top is relative to the containing .f element, the translate relative to the pseudo element's size).

/* do not change any JavaScript */

const template = document.querySelector('#arrow');
document.querySelectorAll('span').forEach(elem => {
  const child = template.content.cloneNode(true).children[0];
  elem.appendChild(child);
});
.f1 { font-size: 10pt; }
.f2 { font-size: 15pt; }
.f3 { font-size: 25pt; }
.f4 { font-size: 30pt; }
.f5 { font-size: 35pt; }
.f6 { font-size: 40pt; }
.f7 { font-size: 45pt; }
.f8 { font-size: 50pt; }
.f9 { font-size: 55pt; }
.f10 { font-size: 60pt; }
.f11 { font-size: 65pt; }
.f12 { font-size: 70pt; }

/* only change css below this line */

.f {
  background: linear-gradient(#e66465 50%, #9198e5 50%);
  display: inline-block;
  position: relative;
}
.f::after {
  content: "⬅";
  color: rgba(255, 0, 0, 0.5);
  font-size: 20pt;
  
  position: absolute;
  display: inline-block;
  right: 0;
  top: 50%;
  padding-left: 2px;
  transform: translateX(100%) translateY(-50%);
}
<p>
Alice drank the potion and she got 
<span class="f f1">bigger</span> and 
<span class="f f2">bigger</span> and 
<span class="f f3">bigger</span> and 
<span class="f f4">bigger</span> and 
<span class="f f5">bigger</span> and 
<span class="f f6">bigger</span> and 
<span class="f f7">bigger</span> and 
<span class="f f8">bigger</span> and 
<span class="f f9">bigger</span> and 
<span class="f f10">bigger</span> and 
<span class="f f11">bigger</span> and 
<span class="f f12">bigger</span> and 
</p>

<!-- only change html below this line -->

<template id="arrow">
  <div />
</template>

enter image description here

Cameron Little
  • 3,487
  • 23
  • 35
  • Thank you for taking the time to answer. Unfortunately the question is not "how do I align an arrow". It's "how to I align a collection of html elements". It also made it clear that hardcoding sizes is out so "right: -22pt;" is not really a solution. The solution needs to work regardless of content. – gman Apr 11 '20 at 11:12
  • Ah, from your wording of "The point being I can not hard code **heights** for each situation." I didn't think horizontal values mattered. I've updated to use a transform to avoid that anyways. That being said, you can apply the same styling I've applied to the pseudo element to the arrow element for the same result. – Cameron Little Apr 11 '20 at 13:10