5

I would like to use HTML and CSS (and if really necessary, some JS) to find a responsive way to put chords above lyrics. I already checked this post: Styling text to make it appear above the line (for chords above the lyrics) Here is what I have so far:

        body {
          padding:20px;
          font-size: 30px;
        }
        .chord{
            position    : absolute;
            top         : -50px;
            width       : 0;
            font-style  : italic;
            font-weight : bold;
            font-size: 50px;
        }

        .chord-lyrics{
            position: relative;
            display: inline-block;
            margin-top: 50px;
        }
<div class="line">
    <div class="chord-lyrics"><span class="chord">C</span> Imagine</div> there's 
    <div class="chord-lyrics"><span class="chord">Cmaj7</span>no</div>
    <div class="chord-lyrics"><span class="chord">F</span>heaven</div>
</div>

The goals:

  1. always keep the chord above the right lyrics
  2. if screen is smaller than the line, each word must overflow on the next line
  3. if the chords are larger than the text below it should create space between the lyrics EDIT:
  4. a chord can also be in the middle of a word

For now, everything works fine for 1. and 2. but not for 3. and this last one is also really important!

Thanks

Edwin ZAP
  • 419
  • 1
  • 4
  • 16
  • 1
    Using `position: absolute` means you'll never really be able to achieve what you want - it removes the element from the flow of the page, so it cannot affect other elements – Luke Apr 15 '21 at 09:09

5 Answers5

3

Another possibility is to use Flexbox:

body {
  padding: 20px;
  font-size: 30px;
}

.container {
  max-width: 450px;
}

.line {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
}

.chord-letter {
  display: flex;
  flex-direction: column;
  padding: 0 5px;
  align-items: center; /* center chord */
}

.chord {
  font-style: italic;
  font-weight: bold;
  font-size: 25px;
}
<div class="container">
  <div class="line">
    <div class="chord-letter"><span class="chord">C</span> Imagine</div> there's
    <div class="chord-letter"><span class="chord">Cmaj7</span>no</div>
    <div class="chord-letter"><span class="chord">F</span>heaven</div>
  </div>
</div>

This code is fully responsive. Each chord-text-combo will be moved to the next line if there's not enough space.

Here is a Fiddle for you to play with.

coreuter
  • 3,331
  • 4
  • 28
  • 74
  • Thanks. I edited my post. I would like also to be able to put a chord in the middle of a word. – Edwin ZAP Apr 15 '21 at 10:04
  • That's easy, just add `align-items: center;` to `.chord-letter`. I'll adjust my answer. – coreuter Apr 15 '21 at 10:05
  • When I said middle, I meant somewhere inside the word ^^. So for example: I[C]magine and make the C to always be above the first letter (so here "m") – Edwin ZAP Apr 15 '21 at 10:09
  • Oh sorry :D mmh.. I don't think that's possible with flexbox. You could add some `padding-left` to `.chord`, but that won't be perfect for every word since the letters have different widths. – coreuter Apr 15 '21 at 10:21
  • I did that with your code: https://jsfiddle.net/tdky7xcs/12/. I put every word in a div and it's working. The only thing is that "Imagine" splits in two on resize – Edwin ZAP Apr 15 '21 at 10:31
1

Using position: absolute removes the elements from the flow of the page and prevents them from having an effect on the other elements.

If you change this to position: relative you can get something close to what you're looking for.

Just as a footnote, using px measurements isn't responsive. You should look to use ems, rems or even vw/vh!

        body {
          padding:20px;
          font-size: 30px;
        }
        .chord{
            position    : relative;
            top         : -50px;
            left        : 50px;
            width       : 0;
            font-style  : italic;
            font-weight : bold;
            font-size: 50px;
        }

        .chord-lyrics{
            position: relative;
            display: inline-block;
            margin-top: 50px;
        }
<div class="line">
    <div class="chord-lyrics"><span class="chord">C</span> Imagine</div> there's 
    <div class="chord-lyrics"><span class="chord">Cmaj7</span>no</div>
    <div class="chord-lyrics"><span class="chord">F</span>heaven</div>
</div>
Luke
  • 1,060
  • 8
  • 19
  • 1
    It helps but the problem is that the chord is never above the lyric. Using left 50px is a bit of cheating because it still creates an unnecessary space on the left side of the word – Edwin ZAP Apr 15 '21 at 09:46
1

Alternatively, "flexbox" can be used.

body {
  padding: 20px;
  font-size: 30px;
}

.line {
  display: flex;
  align-items: flex-end;
  justify-content: start;
  flex-wrap: wrap;
}

.chord {
  font-style: italic;
  font-weight: bold;
  font-size: 50px;
}

.chord-lyrics {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: end;
}

.space {
  margin-right: .3em;
  margin-top: .3em;
  margin-bottom: .3em;
}
<div class="line">
  <div class="chord-lyrics space"><span class="chord">C</span> Imagine</div>
  <span class="space">there's</span>
  <div class="chord-lyrics space"><span class="chord">Cmaj7</span>no</div>
  <div class="chord-lyrics space"><span class="chord">F</span>heaven</div>
  <div class="chord-lyrics space"><span class="chord">C</span> Imagine</div>
  <span class="space">there's</span>
  <div class="chord-lyrics space"><span class="chord">Cmaj7</span>no</div>
  <div class="chord-lyrics space"><span class="chord">F</span>heaven</div>
  <div class="chord-lyrics space"><span class="chord">C</span> Imagine</div>
  <span class="space">there's</span>
  <div class="chord-lyrics space"><span class="chord">Cmaj7</span>no</div>
  <div class="chord-lyrics space"><span class="chord">F</span>heaven</div>
  <div class="chord-lyrics space"><span class="chord">F</span>heaven</div>
</div>

For your second question:

In overflows, the word and the chord behave as a whole, and the chord and word are always centered.

body {
  padding: 20px;
  font-size: 30px;
}

.line {
  display: flex;
  align-items: flex-end;
  justify-content: start;
  flex-wrap: wrap;
}

.chord {
  font-style: italic;
  font-weight: bold;
  font-size: 50px;
}

.chord-lyrics {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: end;
}

.space {
  margin-right: .3em;
  margin-top: .3em;
  margin-bottom: .3em;
}
<div class="line">
  <div class="chord-lyrics space"><span class="chord">C</span> Imagine</div>
  <span class="space">there's</span>
  <div class="chord-lyrics space"><span class="chord">Cmaj7</span>no</div>
  <div class="chord-lyrics space"><span class="chord">F</span>heaven</div>
  <div class="chord-lyrics space"><span class="chord">C</span> Imagine</div>
  <span class="space">there's</span>
  <div class="chord-lyrics space"><span class="chord">Cmaj7</span>no</div>
  <div class="chord-lyrics space"><span class="chord">F</span>heaven</div>
  <div class="chord-lyrics space"><span class="chord">C</span> Imagine</div>
  <span class="space">there's</span>
  <div class="chord-lyrics space"><span class="chord">Cmaj7</span>no</div>
  <div class="chord-lyrics space"><span class="chord">F</span>heaven</div>
  <div class="chord-lyrics space"><span class="chord">F</span>heaven</div>
</div>
BOZ
  • 2,731
  • 11
  • 28
0

I'd rather do smthg like that :

div.part {
    float  : left;
    margin : .3em;
    
}
div.chord {
    font-weight : bolder;
    font-style  : italic;
}
div.lyric {
    text-align  : center;
}

            
  <div class="part">
      <div class="chord">C</div>
      <div class="lyric">Imagine</div>
  </div>
  <div class="part">
      <div class="chord">&nbsp;</div>
      <div class="lyric">there's</div>
  </div>
  <div class="part">
      <div class="chord">Cmaj7</div>
      <div class="lyric">no</div>
  </div>
  <div class="part">
      <div class="chord">F</div>
      <div class="lyric">heaven</div>
  </div>
St3an
  • 726
  • 1
  • 6
  • 21
0

Thanks to everyone, here is what I was able to do:

body {
    padding: 20px;
    font-size: 30px;
}

.line {
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
}

.chord-letter {
    display: flex;
    flex-direction: column;
    align-items: left;
}

.no-space {
    margin-right: 0;
    border: solid 1px red;
}

.space {
    margin-right: 0.33em;
    border: solid 1px green;
}

.chord {
    color: gray;
    font-style: italic;
    font-weight: bold;
    font-size: 1.2em;
    border: solid 1px blue;
}

.no-space .chord {
    margin-right: 0.33em;
}

.word {
    display: flex;
    flex-direction: row;
    align-items: flex-end;
}
<div class="line">
   <div class="word">
      <span class="no-space">Ima</span>
      <div class="chord-letter space"><span class="chord">C</span>gine</div>
   </div>
   <span class="space">there's</span>
   <div class="chord-letter space"><span class="chord">Cmaj7</span>no</div>
   <div class="chord-letter space"><span class="chord">F</span>heaven</div>
   <div class="word">
      <span class="no-space">Ima</span>
      <div class="chord-letter space"><span class="chord">C</span>gine</div>
   </div>
</div>

It is:

  1. Fully responsive
  2. Allow chords inside a word
  3. Avoid breaking the words on wrapping
Edwin ZAP
  • 419
  • 1
  • 4
  • 16