Home > database >  Baseline alignment of absolute child
Baseline alignment of absolute child

Time:10-18

I'm trying to build a Unicode table which can compare glyph blackspace between fonts.

My intention is for user-selected fonts on the table; Obviously, fonts have different (unknown) metrics. So—as per the following example—is it possible to align the children's font to the parents' font's baseline after absolutely positioning the child glyph objects?

#box{
  display: flex;
        justify-content: center;
        align-items: center;
  font-size: 72pt;
  /* dimension ref */
  border: 1px solid blue;
}

#box > span {
  display: inline-flex;
        justify-content: center;
  font-family: serif;
  border: 1px solid #F0F;
}

#box > span > span {
  position: absolute;
  mix-blend-mode: difference;
  font-family: cursive;
  color: red;
  /* alignment ref */
  outline: 1px solid #0F0;
}
<div id="box">
  <span>x<span>x</span></span>
  <span>y<span>y</span></span>
  <span>z<span>z</span></span>
  <span>!<span>!</span></span>
</div>

My preferred solution would be pure CSS, but a scan of the available resources indicates that's unlikely. Are font metrics exposed at all to JavaScript, such that I could just calculate a top or bottom margin and shove it in as a CSS variable?

Otherwise, I'm left pulling relative child glyph objects left (read as: towards flex "start") by half their width plus half the parent width? And that gets messy because I'll need per-character adjustments and that's a time-consuming calculation when I'm displaying 10K glyphs and the user changes fonts…


EDIT: As reference, my system uses "Georgia" as serif and "Comic Sans MS" as cursive. I also am testing initial resulting in Gecko/Firefox, then aligning them to Chromium. Normally this might not matter, but these are areas where different browsers/engines may render with subtle differences. For the above fonts, default baselines in Word align as follows:

xyz! inter-font baseline alignment.

  • "Comic Sans" 'z' and '!' should bleed under the baseline, as does right side of the 'x'.
  • 'y' actually connects above the baseline
  • All glyphs both ascend higher and descend lower than their respective "Georgia" glyph.

CodePudding user response:

Maybe you can do something like this. I've wrapped each "letter" into their own div. Then set both the first span and the child span to position: absolute; and set both of them to bottom: 0; giving them the same baseline.

I also gave the new dives a margin in order to space the letters out a bit. Check out what I did here:

#box{
  display: inline-block;
        justify-content: center;
        align-items: center;
  font-size: 72pt;
  /* dimension ref */
  border: 1px solid blue; 
}

#box > div {
  position: relative;
  height: 100px;
  display: inline-block;
  margin: 30px;
}

#box > div > span {
  display: inline-flex;
        justify-content: center;
  font-family: serif;
  border: 1px solid #F0F;
  position: absolute;
  bottom: 0;
}

#box > div > span > span {
  position: absolute;
  mix-blend-mode: difference;
  font-family: cursive;
  color: red;
  /* alignment ref */
  outline: 1px solid #0F0;
  bottom:0;
}
<div id="box">
<div><span>x<span>x</span></span></div>
<div><span>y<span>y</span></span></div>
<div><span>z<span>z</span></span></div>
<div><span>!<span>!</span></span></div>
</div>

CodePudding user response:

Well, I may have lost the forest for the trees: letter-spacing at -1em for the parent glyph seems to avoid the need for absolute positioning of the child glyph while maintaining the original inline baseline. Flex is also unneeded for the glyph parent.

Additional benefit is that the outlines now conform to the individual font dimensions rather than being homogenized by flex and absolute positioning.

(Of note: mix-blend-mode is imperative to what I'm trying to accomplish, but doesn't seem to be honored by the snippet console for text, only the box model. So, use your imagination or demo elsewhere. Highlighting the text in the snippet result also demos the intended effect.)

div#box {
  font-size: 72pt;
  letter-spacing: -1em;
  /* box ref */
  outline: 1px solid #F0F;
}

#box > span {
  font-family: serif;
  /* dim ref */
  outline: 1px solid #000;
}

span > span {
  mix-blend-mode: difference;
  font-family: cursive;
  color: #0FF;
  letter-spacing: 0em;
  /* dim ref */
  outline: 1px solid #0FF;
}
<div id="box">
  <span>x<span>x</span></span>
  <span>y<span>y</span></span>
  <span>z<span>z</span></span>
  <span>!<span>!</span></span>
</div>

A rare example of em doing what I would expect rather than something bizarre.

CodePudding user response:

Set box position to relative then control absolute children's position with px or %

#box{
    display: flex;
          justify-content: center;
          align-items: center;
    font-size: 72pt;
    /* dimension ref */
    border: 1px solid blue;
    position: relative;
  }
  
  #box > span {
    display: inline-flex;
          justify-content: center;
    font-family: serif;
    border: 1px solid #F0F;
  }
  
  #box > span > span {
    position: absolute;
    mix-blend-mode: difference;
    font-family: cursive;
    color: red;
    /* alignment ref */
    outline: 1px solid #0F0;
    bottom: 1%;
  }
 <div id="box">
    <span>x<span>x</span></span>
    <span>y<span>y</span></span>
    <span>z<span>z</span></span>
    <span>!<span>!</span></span>
  </div>

put them on the side

#box{
    display: flex;
          justify-content: center;
          align-items: center;
    font-size: 72pt;
    /* dimension ref */
    border: 1px solid blue;
    position: relative;
  }
  
  #box > span {
    display: inline-flex;
          justify-content: center;
    font-family: serif;
    border: 1px solid #F0F;
    position: relative;
    width: 70px;
    margin-right: 50px;
  }
  
  #box > span > span {
    position: absolute;
    mix-blend-mode: difference;
    font-family: cursive;
    color: red;
    /* alignment ref */
    outline: 1px solid #0F0;
    bottom: -1%;
    left:  70px;
    width: 50px;
    
  }
 <div id="box">
    <span>x<span>x</span></span>
    <span>y<span>y</span></span>
    <span>z<span>z</span></span>
    <span>!<span>!</span></span>
  </div>

EDIT: regarding your comment:


for that, I think it will be better to put letters in one container, then position both of them absolute with baseline alignment. the following example shows that without any additional positioning, meaning it's the baseline of the font. and you can adjust positioning using bottom

#box{
  display: flex;
  justify-content: center;
  align-items: baseline;
  font-size: 72pt;
  /* dimension ref */
  border: 1px solid blue;
  position: relative;
  height: fit-content;
  padding: 100px;
}

.black {
  position: absolute;
  display: flex;
  text-decoration: underline;
  
  justify-content: center;
  font-family: serif;
  border: 1px solid #F0F;
  letter-spacing: 30px;
}

.red {
  display: flex;
  text-decoration: underline;
  position: absolute;
  mix-blend-mode: difference;
  font-family: cursive;
  color: red;
  border: 1px solid lightgreen;
  letter-spacing: 30px;
 
}
<div id="box">

    <div >XYZ!</div>
    <div >XYZ!</div>
   
  </div>

  • Related