Zoom problems on Anki for iPad ("Double-Zoom" Bug)

Hi everyone,

I’ve encountered a strange bug in the Anki app on my iPad. Initially, the built-in zoom feature works fine when I use it to enlarge the cards. However, when I switch to a different card, the card zooms in again, creating an unpleasant double-zoom effect that makes the text difficult to read and ruins the appearance of the card.

Resetting the zoom to 1.0x or zooming again doesn’t resolve the issue. The problem persists until I exit the deck and return. At that point, the cards look normal again and the zoom function works as expected – until I click on the answer again, which triggers the issue anew.

I’m not sure whether this issue stems from my HTML and CSS setup, whether I’m using the zoom feature incorrectly, or whether it’s a bug within the Anki app itself. I’ve scoured the internet for information, but I haven’t found anything relevant.

Interestingly, this issue does not occur on my iPhone, where the cards remain properly zoomed and readable.

For additional context, I’m using the latest version of Anki on my iPad (25.07.1) and version 25.02.6 on my computer.

For reference, I have included two screen recordings: one from my iPad showcasing this behavior, and another from my iPhone demonstrating smooth zooming and unzooming without any visual problems. Below are the front and back templates for recognition and recall cards, along with my CSS styles. Please note that I am using Tailwind CSS and am unsure whether this is contributing to the problem.

Thank you very much!

iPad Screen Recording:

iPhone Screen Recording:

Front Template (Recognition Card):

<div class="p-4">
  <div
    class="block rounded-lg solarized-bg-base02 text-left solarized-text-base2 shadow-md text-base max-w-xl m-auto"
  >
    <div class="border-b-2 border-[#002b36] px-6 py-3">
      <div class="grid grid-cols-3 grid-rows-1 gap-0 items-center">
        <div class="text-xs solarized-text-base1">
          {{#Frequency}}
          <div
            class="solarized-bg-base01 solarized-text-base2 px-2 py-1 rounded text-xs inline-block"
          >
            {{Frequency}}
          </div>
          {{/Frequency}}
        </div>
        <div class="flex flex-col justify-center items-center">
          {{#Lesson name (Hanzi)}}
          <span
            class="solarized-bg-base2 solarized-text-base02 text-xs font-medium px-2.5 py-0.5 rounded"
          >
            {{Lesson name (Hanzi)}}
          </span>
          {{/Lesson name (Hanzi)}} {{#HSK}}
          <span
            class="solarized-bg-base01 solarized-text-base2 text-xs px-2 py-0.5 rounded mt-1"
          >
            HSK {{HSK}}
          </span>
          {{/HSK}}
        </div>
        <div class="ml-auto flex items-center gap-2">
          {{#Classifier}}
          <span class="solarized-text-base1 text-xs">{{Classifier}}</span>
          {{/Classifier}} {{#Sound}}
          <span class="replay-button" style="display: none">{{Sound}}</span>
          <!-- Custom Material Design play button -->
          <a
            href="#"
            class="group p-2 rounded-full hover:bg-base01 transition sound-button"
            title="Play audio"
          >
            <svg
              xmlns="http://www.w3.org/2000/svg"
              viewBox="0 0 24 24"
              class="w-6 h-6 fill-current solarized-text-base2 group-hover:solarized-text-base0 transition-colors"
            >
              <title>volume-high</title>
              <path
                d="M14,3.23V5.29C16.89,6.15 19,8.83 19,12C19,15.17 16.89,17.84 14,18.7V20.77C18,19.86 21,16.28 21,12C21,7.72 18,4.14 14,3.23M16.5,12C16.5,10.23 15.5,8.71 14,7.97V16C15.5,15.29 16.5,13.76 16.5,12M3,9V15H7L12,20V4L7,9H3Z"
              />
            </svg>
          </a>
          {{/Sound}}
        </div>
      </div>
    </div>
    <div class="p-6">
      <div class="flex items-center justify-between mb-2">
        <h5 class="text-2xl font-medium leading-tight">{{Hanzi}}</h5>
        {{#Traditional}}
        <span
          id="traditional-display"
          class="solarized-text-base1 text-sm"
          style="display: none"
        >
          {{Traditional}}
        </span>
        {{/Traditional}}
      </div>
      <p class="solarized-text-base1">{{Pinyin}}</p>
      {{#Also Written}}
      <p class="solarized-text-base01 text-sm mt-1">Also: {{Also Written}}</p>
      {{/Also Written}}
    </div>
  </div>
</div>

<script>
  (function () {
    const tradSpan = document.getElementById("traditional-display");
    if (!tradSpan) return;

    const simplified = "{{Hanzi}}".trim();
    const traditional = tradSpan.textContent.trim();

    if (simplified !== traditional) {
      tradSpan.style.display = "inline";
    }
  })();

  (function () {
    document.querySelectorAll(".sound-button").forEach((btn) => {
      btn.addEventListener("click", function (e) {
        e.preventDefault();
        const hiddenBtn =
          this.closest(".ml-auto").querySelector(".replay-button");
        if (hiddenBtn) hiddenBtn.click();
      });
    });
  })();

  (function () {
    document.querySelectorAll(".sound-button").forEach((btn) => {
      btn.addEventListener("click", function (e) {
        e.preventDefault();
        // Find the closest parent with class "ml-auto"
        const container = this.closest(".ml-auto");
        if (!container) return;

        // Then find the .replay-button > a inside it
        const replayLink = container.querySelector(".replay-button a");
        if (replayLink) {
          replayLink.click(); // Simulate a click on the hidden replay link
        }
      });
    });
  })();
</script>

Back Template (Recognition Card):

<div class="p-4">
  <div
    class="block rounded-lg solarized-bg-base02 text-left solarized-text-base2 shadow-md text-base max-w-xl m-auto"
  >
    <!-- Same header as front template -->
    <div class="border-b-2 border-[#002b36] px-6 py-3">
      <div class="grid grid-cols-3 grid-rows-1 gap-0 items-center">
        <div class="text-xs solarized-text-base1">
          {{#Frequency}}
          <div
            class="solarized-bg-base01 solarized-text-base2 px-2 py-1 rounded text-xs inline-block"
          >
            {{Frequency}}
          </div>
          {{/Frequency}}
        </div>
        <div class="flex flex-col justify-center items-center">
          {{#Lesson name (Hanzi)}}
          <span
            class="solarized-bg-base2 solarized-text-base02 text-xs font-medium px-2.5 py-0.5 rounded"
          >
            {{Lesson name (Hanzi)}}
          </span>
          {{/Lesson name (Hanzi)}} {{#HSK}}
          <span
            class="solarized-bg-base01 solarized-text-base2 text-xs px-2 py-0.5 rounded mt-1"
          >
            HSK {{HSK}}
          </span>
          {{/HSK}}
        </div>
        <div class="ml-auto flex items-center gap-2">
          {{#Classifier}}
          <span class="solarized-text-base1 text-xs">{{Classifier}}</span>
          {{/Classifier}} {{#Sound}}
          <span class="replay-button" style="display: none">{{Sound}}</span>
          <!-- Custom Material Design play button -->
          <a
            href="#"
            class="group p-2 rounded-full hover:bg-base01 transition sound-button"
            title="Play audio"
          >
            <svg
              xmlns="http://www.w3.org/2000/svg"
              viewBox="0 0 24 24"
              class="w-6 h-6 fill-current solarized-text-base2 group-hover:solarized-text-base0 transition-colors"
            >
              <title>volume-high</title>
              <path
                d="M14,3.23V5.29C16.89,6.15 19,8.83 19,12C19,15.17 16.89,17.84 14,18.7V20.77C18,19.86 21,16.28 21,12C21,7.72 18,4.14 14,3.23M16.5,12C16.5,10.23 15.5,8.71 14,7.97V16C15.5,15.29 16.5,13.76 16.5,12M3,9V15H7L12,20V4L7,9H3Z"
              />
            </svg>
          </a>
          {{/Sound}}
        </div>
      </div>
    </div>

    <div class="p-6">
      <div class="flex items-center justify-between mb-2">
        <h5 class="text-2xl font-medium leading-tight">{{Hanzi}}</h5>
        {{#Traditional}}
        <span
          id="traditional-display"
          class="solarized-text-base1 text-sm"
          style="display: none"
        >
          {{Traditional}}
        </span>
        {{/Traditional}}
      </div>
      <p class="solarized-text-base1">{{Pinyin}}</p>
      {{#Also Written}}
      <p class="solarized-text-base01 text-sm mt-1">Also: {{Also Written}}</p>
      {{/Also Written}}
    </div>

    <hr id="answer" class="border-[#002b36]" />

    <div class="block rounded-b-lg solarized-bg-base3">
      <div class="p-6">
        <div class="mb-4">
          <h5
            class="text-xl font-medium leading-tight solarized-text-base02 mb-2"
          >
            {{French}}
          </h5>
        </div>

        {{#Notes}}
        <div class="mb-4">
          <hr
            class="w-48 h-px mx-auto my-4 solarized-bg-base2 border-0 rounded"
          />
          <div class="solarized-text-base01 text-sm">{{Notes}}</div>
        </div>
        {{/Notes}} {{#Example 1 (Chinese)}}
        <div class="inline-flex items-center justify-center w-full mt-6 mb-4">
          <hr class="w-full h-px solarized-bg-base2 border-0" />
          <span
            class="absolute px-3 font-medium solarized-text-base02 solarized-bg-base3"
          >
            Exemples
          </span>
        </div>
        <div class="space-y-3">
          <div class="solarized-text-base01 text-sm">
            <div class="font-medium">{{Example 1 (Chinese)}}</div>
            {{#Example 1 (French)}}
            <div class="text-xs mt-1 solarized-text-base00">
              {{Example 1 (French)}}
            </div>
            {{/Example 1 (French)}}
          </div>
          {{#Example 2 (Chinese)}}
          <div class="solarized-text-base01 text-sm">
            <div class="font-medium">{{Example 2 (Chinese)}}</div>
            {{#Example 2 (French)}}
            <div class="text-xs mt-1 solarized-text-base00">
              {{Example 2 (French)}}
            </div>
            {{/Example 2 (French)}}
          </div>
          {{/Example 2 (Chinese)}} {{#Example 3 (Chinese)}}
          <div class="solarized-text-base01 text-sm">
            <div class="font-medium">{{Example 3 (Chinese)}}</div>
            {{#Example 3 (French)}}
            <div class="text-xs mt-1 solarized-text-base00">
              {{Example 3 (French)}}
            </div>
            {{/Example 3 (French)}}
          </div>
          {{/Example 3 (Chinese)}}
        </div>
        {{/Example 1 (Chinese)}}
      </div>
    </div>
  </div>
</div>

<script>
  (function () {
    const tradSpan = document.getElementById("traditional-display");
    if (!tradSpan) return;

    const simplified = "{{Hanzi}}".trim();
    const traditional = tradSpan.textContent.trim();

    if (simplified !== traditional) {
      tradSpan.style.display = "inline";
    }
  })();

  (function () {
    document.querySelectorAll(".sound-button").forEach((btn) => {
      btn.addEventListener("click", function (e) {
        e.preventDefault();
        const hiddenBtn =
          this.closest(".ml-auto").querySelector(".replay-button");
        if (hiddenBtn) hiddenBtn.click();
      });
    });
  })();

  (function () {
    document.querySelectorAll(".sound-button").forEach((btn) => {
      btn.addEventListener("click", function (e) {
        e.preventDefault();
        // Find the closest parent with class "ml-auto"
        const container = this.closest(".ml-auto");
        if (!container) return;

        // Then find the .replay-button > a inside it
        const replayLink = container.querySelector(".replay-button a");
        if (replayLink) {
          replayLink.click(); // Simulate a click on the hidden replay link
        }
      });
    });
  })();
</script>

Front Template (Recall Card):

<div class="p-4">
  <div
    class="block rounded-lg solarized-bg-base02 text-left solarized-text-base2 shadow-md text-base max-w-xl m-auto"
  >
    <!-- Header (same as Recognition cards) -->
    <div class="border-b-2 border-[#002b36] px-6 py-3">
      <div class="grid grid-cols-3 grid-rows-1 gap-0 items-center">
        <div class="text-xs solarized-text-base1">
          {{#Frequency}}
          <div
            class="solarized-bg-base01 solarized-text-base2 px-2 py-1 rounded text-xs inline-block"
          >
            {{Frequency}}
          </div>
          {{/Frequency}}
        </div>
        <div class="flex flex-col justify-center items-center">
          {{#Lesson name (Hanzi)}}
          <span
            class="solarized-bg-base2 solarized-text-base02 text-xs font-medium px-2.5 py-0.5 rounded"
          >
            {{Lesson name (Hanzi)}}
          </span>
          {{/Lesson name (Hanzi)}} {{#HSK}}
          <span
            class="solarized-bg-base01 solarized-text-base2 text-xs px-2 py-0.5 rounded mt-1"
          >
            HSK {{HSK}}
          </span>
          {{/HSK}}
        </div>
        <div class="ml-auto flex items-center gap-2">
          {{#Classifier}}
          <span class="solarized-text-base1 text-xs">{{Classifier}}</span>
          {{/Classifier}}
        </div>
      </div>
    </div>

    <!-- Main Recall Prompt -->
    <div class="p-6 flex flex-col items-center gap-3 text-center">
      <div class="text-xl font-semibold">{{French}}</div>
    </div>
    <div class="block rounded-b-lg solarized-bg-base3">
      <div class="p-6">
        <div class="mb-4">
          <h5
            class="text-xl font-medium leading-tight solarized-text-base02 mb-2"
          >
            {{#Silhouette}}
            <div class="flex items-center justify-between mb-2">
              <h5 class="text-2xl font-medium leading-tight">{{Silhouette}}</h5>
            </div>
            {{/Silhouette}} {{#Pinyin}}
            <p class="solarized-text-base1">{{hint:Pinyin}}</p>
            {{/Pinyin}}
          </h5>
        </div>
      </div>
    </div>
  </div>
</div>

Back Template (Recall Card):

<div class="p-4">
  <div
    class="block rounded-lg solarized-bg-base02 text-left solarized-text-base2 shadow-md text-base max-w-xl m-auto"
  >
    <!-- Same header as front template -->
    <div class="border-b-2 border-[#002b36] px-6 py-3">
      <div class="grid grid-cols-3 grid-rows-1 gap-0 items-center">
        <div class="text-xs solarized-text-base1">
          {{#Frequency}}
          <div
            class="solarized-bg-base01 solarized-text-base2 px-2 py-1 rounded text-xs inline-block"
          >
            {{Frequency}}
          </div>
          {{/Frequency}}
        </div>
        <div class="flex flex-col justify-center items-center">
          {{#Lesson name (Hanzi)}}
          <span
            class="solarized-bg-base2 solarized-text-base02 text-xs font-medium px-2.5 py-0.5 rounded"
          >
            {{Lesson name (Hanzi)}}
          </span>
          {{/Lesson name (Hanzi)}} {{#HSK}}
          <span
            class="solarized-bg-base01 solarized-text-base2 text-xs px-2 py-0.5 rounded mt-1"
          >
            HSK {{HSK}}
          </span>
          {{/HSK}}
        </div>
        <div class="ml-auto flex items-center gap-2">
          {{#Classifier}}
          <span class="solarized-text-base1 text-xs">{{Classifier}}</span>
          {{/Classifier}} {{#Sound}}
          <span class="replay-button" style="display: none">{{Sound}}</span>
          <!-- Custom Material Design play button -->
          <a
            href="#"
            class="group p-2 rounded-full hover:bg-base01 transition sound-button"
            title="Play audio"
          >
            <svg
              xmlns="http://www.w3.org/2000/svg"
              viewBox="0 0 24 24"
              class="w-6 h-6 fill-current solarized-text-base2 group-hover:solarized-text-base0 transition-colors"
            >
              <title>volume-high</title>
              <path
                d="M14,3.23V5.29C16.89,6.15 19,8.83 19,12C19,15.17 16.89,17.84 14,18.7V20.77C18,19.86 21,16.28 21,12C21,7.72 18,4.14 14,3.23M16.5,12C16.5,10.23 15.5,8.71 14,7.97V16C15.5,15.29 16.5,13.76 16.5,12M3,9V15H7L12,20V4L7,9H3Z"
              />
            </svg>
          </a>
          {{/Sound}}
        </div>
      </div>
    </div>

    <div class="p-6 flex flex-col items-center gap-3 text-center">
      <!-- Main Recall Prompt -->
      <div class="text-xl font-semibold">{{French}}</div>
    </div>

    <hr id="answer" class="border-[#002b36]" />

    <div class="block rounded-b-lg solarized-bg-base3">
      <div class="p-6">
        <div class="mb-4">
          <h5
            class="text-xl font-medium leading-tight solarized-text-base02 mb-2"
          >
            <div class="flex items-center justify-between mb-2">
              <h5 class="text-2xl font-medium leading-tight">{{Hanzi}}</h5>
              {{#Traditional}}
              <span
                id="traditional-display"
                class="solarized-text-base1 text-sm"
                style="display: none"
              >
                {{Traditional}}
              </span>
              {{/Traditional}}
            </div>
            <p class="solarized-text-base1">{{Pinyin}}</p>
            {{#Also Written}}
            <p class="solarized-text-base01 text-sm mt-1">
              Also: {{Also Written}}
            </p>
            {{/Also Written}}
          </h5>
        </div>

        {{#Notes}}
        <div class="mb-4">
          <hr
            class="w-48 h-px mx-auto my-4 solarized-bg-base2 border-0 rounded"
          />
          <div class="solarized-text-base01 text-sm">{{Notes}}</div>
        </div>
        {{/Notes}} {{#Example 1 (Chinese)}}
        <div class="inline-flex items-center justify-center w-full mt-6 mb-4">
          <hr class="w-full h-px solarized-bg-base2 border-0" />
          <span
            class="absolute px-3 font-medium solarized-text-base02 solarized-bg-base3"
          >
            Exemples
          </span>
        </div>
        <div class="space-y-3">
          <div class="solarized-text-base01 text-sm">
            <div class="font-medium">{{Example 1 (Chinese)}}</div>
            {{#Example 1 (French)}}
            <div class="text-xs mt-1 solarized-text-base00">
              {{Example 1 (French)}}
            </div>
            {{/Example 1 (French)}}
          </div>
          {{#Example 2 (Chinese)}}
          <div class="solarized-text-base01 text-sm">
            <div class="font-medium">{{Example 2 (Chinese)}}</div>
            {{#Example 2 (French)}}
            <div class="text-xs mt-1 solarized-text-base00">
              {{Example 2 (French)}}
            </div>
            {{/Example 2 (French)}}
          </div>
          {{/Example 2 (Chinese)}} {{#Example 3 (Chinese)}}
          <div class="solarized-text-base01 text-sm">
            <div class="font-medium">{{Example 3 (Chinese)}}</div>
            {{#Example 3 (French)}}
            <div class="text-xs mt-1 solarized-text-base00">
              {{Example 3 (French)}}
            </div>
            {{/Example 3 (French)}}
          </div>
          {{/Example 3 (Chinese)}}
        </div>
        {{/Example 1 (Chinese)}}
      </div>
    </div>
  </div>
</div>

<script>
  (function () {
    const tradSpan = document.getElementById("traditional-display");
    if (!tradSpan) return;

    const simplified = "{{Hanzi}}".trim();
    const traditional = tradSpan.textContent.trim();

    if (simplified !== traditional) {
      tradSpan.style.display = "inline";
    }
  })();

  (function () {
    document.querySelectorAll(".sound-button").forEach((btn) => {
      btn.addEventListener("click", function (e) {
        e.preventDefault();
        const hiddenBtn =
          this.closest(".ml-auto").querySelector(".replay-button");
        if (hiddenBtn) hiddenBtn.click();
      });
    });
  })();

  (function () {
    document.querySelectorAll(".sound-button").forEach((btn) => {
      btn.addEventListener("click", function (e) {
        e.preventDefault();
        // Find the closest parent with class "ml-auto"
        const container = this.closest(".ml-auto");
        if (!container) return;

        // Then find the .replay-button > a inside it
        const replayLink = container.querySelector(".replay-button a");
        if (replayLink) {
          replayLink.click(); // Simulate a click on the hidden replay link
        }
      });
    });
  })();
</script>

Styling:

@import url("_tailwind.css");

/* Base card styling */
.card {
  font-size: 24px;
  text-align: center;
  background-color: #FFF;
  -webkit-text-size-adjust: 100%; /* try 'none' if 100% still inflates */
  text-size-adjust: 100%;
}

/* Frequency badge styling */
.frequency-badge {
  display: inline-block;
  font-size: 0.75rem;
  line-height: 1rem;
}

/* HSK level badge styling */
.hsk-badge {
  margin-top: 0.25rem;
  font-size: 0.75rem;
}

/* Traditional character variant styling */
.traditional-variant {
  opacity: 0.8;
  font-size: 0.875rem;
}

/* Alternative writing style */
.also-written {
  font-style: italic;
  opacity: 0.7;
}

/* Notes section divider */
.notes-section {
  border-top: 1px solid #586e75;
  margin: 1rem 0;
  padding-top: 1rem;
}

/* Examples section styling */
.example-section {
  border-top: 1px solid #586e75;
  margin-top: 1.5rem;
  padding-top: 1rem;
}

/* Individual example item */
.example-item {
  margin-bottom: 0.75rem;
}

/* Chinese example text */
.example-chinese {
  font-weight: 500;
  margin-bottom: 0.25rem;
}

/* French translation text */
.example-french {
  font-size: 0.875rem;
  opacity: 0.8;
}

/* Solarized color palette classes */
.solarized-bg-base03 {
  background-color: #012B36;
}
.solarized-bg-base02 {
  background-color: #073642;
}
.solarized-bg-base01 {
  background-color: #586e75;
}
.solarized-bg-base00 {
  background-color: #657b83;
}
.solarized-bg-base0 {
  background-color: #839496;
}
.solarized-bg-base1 {
  background-color: #93a1a1;
}
.solarized-bg-base2 {
  background-color: #eee8d5;
}
.solarized-bg-base3 {
  background-color: #fdf6e3;
}

.solarized-text-base03 {
  color: #012B36;
}
.solarized-text-base02 {
  color: #073642;
}
.solarized-text-base01 {
  color: #586e75;
}
.solarized-text-base00 {
  color: #657b83;
}
.solarized-text-base0 {
  color: #839496;
}
.solarized-text-base1 {
  color: #93a1a1;
}
.solarized-text-base2 {
  color: #eee8d5;
}
.solarized-text-base3 {
  color: #fdf6e3;
}

/* Solarized accent colors */
.solarized-bg-yellow {
  background-color: #B58901;
}
.solarized-bg-orange {
  background-color: #CB4B15;
}
.solarized-bg-red {
  background-color: #DC322F;
}
.solarized-bg-magenta {
  background-color: #D23782;
}
.solarized-bg-violet {
  background-color: #6C71C4;
}
.solarized-bg-blue {
  background-color: #258BD2;
}
.solarized-bg-cyan {
  background-color: #2AA198;
}
.solarized-bg-green {
  background-color: #859901;
}

.solarized-text-yellow {
  color: #B58901;
}
.solarized-text-orange {
  color: #CB4B15;
}
.solarized-text-red {
  color: #DC322F;
}
.solarized-text-magenta {
  color: #D23782;
}
.solarized-text-violet {
  color: #6C71C4;
}
.solarized-text-blue {
  color: #258BD2;
}
.solarized-text-cyan {
  color: #2AA198;
}
.solarized-text-green {
  color: #859901;
}
1 Like

If I recall correctly, some years back, Apple changed iPadOS so that it no longer honors webkitTextSizeAdjust, so AnkiMobile had to implement a different way of scaling the text. It works by rewriting exist font-size definitions to make them relative to the document size, and then adjusts that size to scale the page. I’m guessing your tailwind script is being executed after that happens. If you temporarily remove it from your template, does the issue go away? If you use dimensions like px instead of rem, does that help?

Also, while not a solution to your problem per se, have you considered adjusting your templates to alter the default font size per platform? You could have the iPad automatically show larger text, so you don’t need to manually zoom in.

Please see Styling & HTML - Anki Manual

1 Like

Hey @dae, thanks so much for your reply. I’ll check out your suggestions and try removing the Tailwind script to see if it fixes the issue. I’ll keep you posted.

Thanks again for your help @dae! I wanted to share an update in case anyone else runs into the same problem.

As it turns out, you were right—removing Tailwind fixed the issue. After doing so, the cards started behaving properly on the iPad, and the double zoom disappeared.

I did try your first suggestion of switching from rem to px. While that prevented the double zoom, I couldn’t get the styling to look the way I wanted. The proportions and spacing always felt off with Tailwind as my CSS. I also experimented with a hybrid approach (px for small labels and rem for everything else), but I wasn’t happy with the results. So, I didn’t stick with that approach.

Instead, I went with your second suggestion of adjusting the default root font size on the iPad so that I wouldn’t need to use Anki’s zoom feature. Now, the cards appear larger on iPads by default, and, since Tailwind’s utilities remain rem-based, all the proportions scale correctly. Everything stays consistent across devices, and the double-zoom glitch is gone.

Here’s the approach in short:

  1. Kept the compiled Tailwind CSS import:

    @import "_tailwind.css";
    
    
  2. Added a platform-detection script at the bottom of each template (Recognition/Recall, Front/Back):

    <script>
    (function () {
      var ua = navigator.userAgent || "";
      var isIPad =
        /iPad/.test(ua) ||
        (navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);
      var isIPhone = /iPhone|iPod/.test(ua);
    
      var root = document.documentElement;
      if (isIPad) {
        root.classList.add("platform-ipad");
      } else if (isIPhone) {
        root.classList.add("platform-iphone");
      }
    })();
    </script>
    
    
  3. Adjusted the base font size in CSS:

    :root { font-size: 16px; }
    html.platform-ipad { font-size: 20px; }
    
    

With this setup, the cards look the same across platforms, and on iPad they’re simply larger by default — no need to rely on zoom anymore. :slightly_smiling_face:

3 Likes