I want to implement dynamic highlighting and light/dark mode switching buttons in Anki HTML/CSS

issue

I want to implement dynamic UI design in a learning app called Anki.

Overview

I am having trouble implementing dynamic style changes using Anki’s HTML/CSS customization features. The two features I want to implement are as follows.

① Switching pneumorphism expression for each part of speech

For fields that may display multiple parts of speech at the same time, such as “verb, noun, adjective, adverb”, I want the text background to be highlighted only when it contains a “verb”. All parts of speech are always visible. Text data may be single, as in “verb”, or it may be multiple, as in “verb/adjective”, separated by a diagonal line. If there is a slanted line, we will go through the process of breaking up the text.

② Ability to switch between light and dark modes

I was able to implement the button itself, but when switching modes, it does not switch the background or shadow color, etc. I am struggling to apply styles. I am looking for a way to achieve this using only CSS, or if necessary, working with JS. We are aware that Anki itself can be configured to switch modes, but this is a feature we would like to implement.

The current HTML and CSS code is pasted below. I would appreciate your advice on how to successfully achieve this in this implementation direction.


Editing code (HTML)

<!-- 表面と裏面まとめて -->
<div class="card-container">

  <div class="part-of-speech">
    <span class="pos" data-pos="動詞">動詞</span>
    <span class="pos" data-pos="名詞">名詞</span>
    <span class="pos" data-pos="形容詞">形容詞</span>
    <span class="pos" data-pos="副詞">副詞</span>
  </div>

  <!-- モード切替ボタン(右下、ニューモーフィズム囲い) -->
  <div class="part-of-speech">
    <label class="mode-toggle">
      <input type="checkbox" id="modeToggle" hidden>
      <div class="mode-toggle-track">
        <div class="mode-toggle-thumb"></div>
      </div>
    </label>
  </div>
</div>

<script>
  const posElements = document.querySelectorAll('.pos');
  posElements.forEach(el => {
    const value = el.dataset.pos;
    if (value.includes('動詞')) {
      el.classList.add('active');
    }
  });
</script>

<script>
  const toggle = document.getElementById('modeToggle');
  toggle.addEventListener('change', function () {
    document.body.classList.toggle('light-mode', toggle.checked);
  });
</script>


Editing code( CSS )

html {
  font-size: 16px;
  box-sizing: border-box;
}
*, *::before, *::after {
  box-sizing: inherit;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
body {
  background-color: #2B2A2B;
  color: #f8f8ff;
  font-family: Arial, sans-serif;
  margin: 0;
  padding: 16px;
  text-align: center;
}

/* --- カード全体 --- */
.card-container {
  margin: 0 auto;
  padding: 12px;
  border-radius: 10px;
  background: #2B2A2B;
  box-shadow: 4px 4px 8px #1A191A, -4px -4px 8px #3C3B3C;
  text-align: center;
  position: relative;
  max-width: 600px;
  width: 95vw;
}

/* --- 品詞部分 --- */
.part-of-speech {
  display: flex;
  justify-content: center;
  align-items: stretch;
  margin-bottom: 1rem;
  padding: 10px;
  border-radius: 15px;
  background: #2B2A2B;
  box-shadow: inset 4px 4px 8px #1A191A, inset -4px -4px 8px #3C3B3C;
  text-align: center;
  width: 95%;
  margin-left: auto;
  margin-right: auto;
}
.part-of-speech .pos {
  flex: 1;
  padding: 0px; /* ← 統一パディングに変更 */
  font-size: 13px;
  color: #E0E0E0;
  background-color: transparent;
  border-left: 1px solid #444;
  transition: background-color 0.3s ease;
}
.part-of-speech .pos:first-child {
  border-left: none;
}
.part-of-speech .pos.active {
  background-color: #FF5D97;
  color: #ffffff;
  border-radius: 5px;
}

/* ===== モード切替ボタン(新構成) ===== */
.mode-toggle-container {
  position: absolute;
  bottom: 12px;
  right: 12px;
  padding: 6px;
  border-radius: 999px;
  background: #2B2A2B;
  box-shadow: 6px 6px 12px #1A191A, -6px -6px 12px #3C3B3C;
  z-index: 5;
}

.mode-toggle {
  display: inline-block;
  height: 32px;
  width: 64px;
  border-radius: 999px;
  overflow: hidden;
}

.mode-toggle-track {
  width: 100%;
  height: 100%;
  border-radius: 999px;
  background-color: #2B2A2B;
  background-image: url('https://i.pinimg.com/736x/6f/6d/c7/6f6dc70a3114dfc5796c1d0b270938dc.jpg');
  background-size: cover;
  background-position: center;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: inset 1px 1px 3px #111111, inset -1px -1px 3px #111111;
  transition: all 0.4s ease;
}

.mode-toggle-thumb {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-image: url('https://i.pinimg.com/736x/a4/47/d8/a447d8e871c6a94e1e2bf17dc6cef8a5.jpg');
  background-size: cover;
  background-position: center;
  box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
  transform: translateX(-18px);
  transition: all 0.4s ease;
  flex-shrink: 0;
}

#modeToggle:checked + .mode-toggle-track {
  background-color: #DFE8F3;
  background-image: url('https://i.pinimg.com/736x/5e/b8/c8/5eb8c8a3c1fef76c4c88a92c30122616.jpg');
  box-shadow: inset 1px 1px 3px #CCCCCC, inset -1px -1px 3px #CCCCCC;
}
#modeToggle:checked + .mode-toggle-track .mode-toggle-thumb {
  background-image: url('https://i.pinimg.com/736x/83/ac/76/83ac76eabfee934e1f764805930ac786.jpg');
  transform: translateX(18px);
}

/* デフォルト:ダークモード */
body {
  background-color: #2B2A2B;
  color: #f8f8ff;
}

.card-container {
  background: #2B2A2B;
  box-shadow: 4px 4px 8px #1A191A, -4px -4px 8px #3C3B3C;
}

.part-of-speech {
  background: #2B2A2B;
  box-shadow: inset 4px 4px 8px #1A191A, inset -4px -4px 8px #3C3B3C;
}

/* ライトモード時のスタイル */
body.light-mode {
  background-color: #DFE8F3;
  color: #2B2A2B;
}

body.light-mode .card-container {
  background: #DFE8F3;
  box-shadow: 4px 4px 8px #B0C4DE, -4px -4px 8px #ffffff;
}

body.light-mode .part-of-speech {
  background: #DFE8F3;
  box-shadow: inset 4px 4px 8px #B0C4DE, inset -4px -4px 8px #ffffff;
}


What I tried

● I edited with GPT-4.5, but could not fully implement the dynamic features
● I also tried downloading JS from “collection.media”, but could not reproduce it due to lack of knowledge (see below).

For switching between light and dark modes you can use something like this:

<button onclick="document.documentElement.classList.toggle('night-mode')
;document.body.classList.toggle('nightMode');document.body.classList.toggle('night_mode');">🌓</button>

as for the part of speech highlighting, a particular implementation would depend on how the contents of your part-of-speech field are formatted. Can you provide some examples of that?

1 Like

Supposing that there are no other “/” characters present in the field you’re talking about (I’m going to refer to it by {{posf}} here), this can be achieved by the following.

parts = `{{posf}}`.replaceAll("/", "<br>")

This replaces all / with newline characters. Now, you can include this code in a particular div you want (say it has id “pos”) with the following code.

document.getElementById("pos").innerHTML = parts

This will get rid of any previously present data in this div, so modify the “= parts” bit accordingly.

1 Like

Thank you @Eltaurus!!

This class field(part-of-speech field) fits these data examples.


part-of-speech English word
動詞 reduce
名詞 situation
名詞/動詞 value
形容詞/名詞 cosmetic
名詞/動詞 practice

If separated by “/”, break it down and highlight the applicable field.

1 Like

Yes, I think it’s possible to do what you want without JS.
Here’s the HTML part:

  <div class="part-of-speech" data-pos="{{part-of-speech}}">
    <span class="pos" data-pos="動詞">動詞</span>
    <span class="pos" data-pos="名詞">名詞</span>
    <span class="pos" data-pos="形容詞">形容詞</span>
    <span class="pos" data-pos="副詞">副詞</span>
  </div>

and here is CSS:

.part-of-speech[data-pos*="動詞"] > [data-pos="動詞"],
.part-of-speech[data-pos*="名詞"] > [data-pos="名詞"],
.part-of-speech[data-pos*="形容詞"] > [data-pos="形容詞"],
.part-of-speech[data-pos*="副詞"] > [data-pos="副詞"] {
  background: lightblue;
}

I wasn’t sure, which part of your original css corresponded to the desired highlight style, so I used simple lighblue background as a placeholder. Let me know, if you’ll need assistance in making your styles work with this selector or have any other questions regarding this solution.

1 Like

Thank you @Eltaurus !!!

We made it happen !!!:sob::sob::sob:
You are a genius !!!:heart_hands::heart_hands::heart_hands:
I’m sad I can’t share this excitement with you. Truly you are a god.:heart_hands::heart_hands::heart_hands:

1 Like

Always happy to help :smiling_face: