Maintain space across front and back and across platforms

I have designed a few new decks, they all have an <hr> in the front and back. However, due to different content in both sides the line appears a bit lower or higher in one of the sides. I have adjusted it manually with <br> and </p> and it looks mostly ok (there’s a bit of a difference, but it’s tolerable, and some cards still are very misaligned, but that’s because there’s more content in one side than the other). But when I review the cards on AnkiDroid the spacing is not the same, and there’s a much clearer difference in the place the line appears

I was wondering if there is a way to set the place where the line should appear without using these tags, so that the distance from the top o the card is always preserved and, possible, it would be the same in Android as well.

Thanks!

(I’m on Windows and using the latest version of Anki (Qt6) and AnkiDroid.)

It’s a bit hard to understand the problem you’re having from just your description. Could you post your card template’s front, back and styling so we can see exactly what kind of html and css you’re using?

Plus, if you can, screenshots of the cards for which you are facing this issue.

I’m not at my computer right now, I can upload a note later for you to see.

However, I will try to explain it better. The only thing I want is to set (in absolute terms) the place in the card where the <hr> line appears. For example, it could appear in the middle of the screen, or at 75% height of the screen, or 200px from the top of the screen, etc.

Right now, since the front and back have different content, it appears at a different height, because its position is determined relatively, depending on the space the previous sections occupy.

The front could be something like this:

<br><span class="prompt">{{Field1}} <br>{{Field2}}</span></p>
<img src=_img1.svg><br><br>
<hr>
{{Field4}}

The back:

{{Audio}}
{{Sentence}}<br>
<br><span class="prompt">{{Field1}} <br>{{Field2}}</span></p>
<img src=_img1.svg><br>
<hr>
{{Field5}}

So what I’d like is for <hr> to appear always at the same height (front and back). I can mostly get this done with <br>, but then when I go to AnkiDroid the results are different.

Hope it’s clearer now. Will upload a note later if needed.

Thansk!

Thanks, I see what you want now.

There’s several options among which I think the simplest is using the css attribute visibility: hidden: visibility - CSS: Cascading Style Sheets | MDN

Using that, you put {{Audio}} and {{Sentence}} on the front as well but make them invisible.

Audio autoplay is on

If you want your audio to autoplay on the card back but not the card front, then you can include it only in the back but commented out like so:

Front

<div style="visibility: hidden">
{{Sentence}}
</div>
<br><span class="prompt">{{Field1}} <br>{{Field2}}</span></p>
<img src=_img1.svg>
<hr>
{{Field4}}

Back

<div>
<!--{{Audio}}-->
{{Sentence}}
</div>
<br><span class="prompt">{{Field1}} <br>{{Field2}}</span></p>
<img src=_img1.svg>
{{Field5}}

Audio autoplay is off

If you’re not using autoplay and instead always press then button to play the audio, then you can just include both {{Audio}} and {{Sentence}} in the front and back:

Front

<div style="visibility: hidden">
{{Audio}}
{{Sentence}}
</div>
<br><span class="prompt">{{Field1}} <br>{{Field2}}</span></p>
<img src=_img1.svg>
<hr>
{{Field4}}

Back

<div>
{{Audio}}
{{Sentence}}
</div>
<br><span class="prompt">{{Field1}} <br>{{Field2}}</span></p>
<img src=_img1.svg>
{{Field5}}
3 Likes

I see, thanks! I will try to use that.

However, my examples were very simplified. The actual front and back of my cards are not that simple and include different scripts on each side, etc. Having all the code on both sides would make it a bit harder to manage, I think.

You mentioned there are other ways to do this?

If you want to avoid duplicating a lot of code and elements in your back template, you could adopt the style where you

  1. include all content in your front template, but hide some of it using visibility: hidden or display: none
  2. use {{FrontSide}} in the back template and show the hidden content with javascript editing the styling

Depending on how your template actually looks this could make it easier to manage the content as you only need to edit it once on the front side.

Front

<!--Stuff you only show in the back before the hr is made invisible-->
<div style="visibility: hidden;" class="make-visible-in-back" >
{{Sentence}}
</div>
<!--Stuff you want to make invisible in the back but keep rendered for the hr positioning-->
<div class="make-invisible-in-back">
{{Field6}}
</div>
<!--Stuff that is visible on both front and back needs no div container-->
<br><span class="prompt">{{Field1}} <br>{{Field2}}</span></p>
<img src=_img1.svg>
<hr>

<!--Other stuff you want to show in the back only-->
<div style="display: none;" class="display-in-back">
{{Field5}}
</div>
<!--Stuff you show in the front but not in the back -->
<div class="undisplay-in-back">
{{Field4}}
</div>

<script>
  // javascript you want to run in both the front and back

  // Or if you need it, use this variable as a condition to prevent stuff from running twice
  var isBackside = !!document.getElementById("back-side")
</script>

Back

Make the invisible elements visible, display selected elements, undisplay others, running either all of the front side javascript again or only a part of it

<!--Helper div that'll let the front side scripts detect if they are running in the front or back-->
<div style="display: none:" id="back-side"/>
<!-- Include entire front side, this means the javascript in there is run a second time-->
{{FrontSide}}
<!--Audio is the one exception, you can't put it in the front template or it will autoplay even if it doesn't render any html-->
{{Audio}}

<script>
  document.querySelectorAll(".make-visible-in-back").forEach((element) => {
    element.style.visibility = "visible";
  });
  document.querySelectorAll(".make-invisible-in-back").forEach((element) => {
    element.style.visibility = "hidden";
  });
  document.querySelectorAll(".display-in-back").forEach((element) => {
    element.style.display = "block";
  });
  document.querySelectorAll(".undisplay-in-back").forEach((element) => {
    element.style.display = "none";
  });

  // Plus any other javascript code you want to run in the back that isn't needed in the front
</script>


The other ways I mentioned would be setting all the content before the <hr> into a div and you force the div height to some preset value. The downside here is that your content may not fit whatever hard limit you set for this container.

The visibility: hidden is better since it will adjust to the size of the content, essentially setting the height of the empty space using the rendered elements.

Front and Back

<div style="content">
Front or back content here
</div>
<br><span class="prompt">{{Field1}} <br>{{Field2}}</span></p>
<img src=_img1.svg>
<hr>
Stuff after hr

Styling

.content {
  // Height at 50% of the viewport height
  // height: 50vh
  // or a specified pixel amount
  // height: 200px
  // or in rem units
  // height: 20rem
}
2 Likes

Thank you! I am going to experiment with these options and see what works.

Any idea why the result looks different on desktop and on AnkiDroid?

Another option is to give the HR a class and then target it with Styling & HTML - Anki Manual