[A/B-Testing] Ändern der übergeordneten CSS-Klasse basierend auf der Experimentvariable

Wir haben ein bestehendes Theme, das wir testen möchten. Ein Beispiel wäre das Testen verschiedener Stile für die Themenlistenansicht. Dafür verwenden wir Google Optimize A/B-Tests. Derzeit planen wir, 50 % der Nutzer das Theme unverändert zu zeigen und den Rest mit dem aktualisierten Theme. Original und Variante sollten im selben Theme definiert werden, da wir nur mit einem kleinen Teil experimentieren. Das Problem ist, dass die übergeordneten CSS-Klassen denselben Namen haben und wir diese Klassen basierend auf einer spezifischen Variable unterschiedlich stylen möchten. Wie können wir separate Styles auf verschiedene Vorlagen anwenden, wenn sie denselben übergeordneten Klassennamen teilen?

Nachfolgend finden Sie ein vereinfachtes Szenario dessen, was wir erreichen möchten:

Angenommen, ich habe ein Theme, in dem der Stil der Themenliste in common/common.scss so definiert ist:

.topic-list {
  tbody {
    border: none;
  }
  tr {
    border: none;
  }
  .example-div {
    border: none;
  }
}

In meiner Variante möchte ich dies so festlegen:

.topic-list {
  tbody {
    display: block;
    tr {
      display: block;
    }
  }
  .example-div {
    border: 2px solid black;
  }
  .another-example-div { 
    font-size: 10px;
  }
}

Die überschriebenen Handlebar-Dateien sehen so aus:

javascripts/discourse/templates/list/custom-topic-list-item.hbr

<div class='example-div'>
  Hallo
</div>

javascripts/discourse/templates/list/variant-custom-topic-list-item.hbr

<div class='example-div'>
  Hallo,
  <div class='another-example-div'>
    Freut mich, Sie kennenzulernen
  </div>
</div>

Der Klassenname topic-list wird in der Discourse-Komponente erwähnt, aber die Struktur sieht nach dem Rendern so aus:

<table class="topic-list">
  <tr class="topic-list-item">
   <div class='example-div'>
      Hallo
    </div>
  </tr>
</table>

Ich möchte eine dieser Dateien abhängig von der Benutzer-ID in meiner Header-Datei rendern:
common/header.html

const { findRawTemplate } = require("discourse-common/lib/raw-templates");
const user_id = api.getCurrentUser().id
 
api.modifyClass('component:topic-list-item', {
  renderTopicListItem() {
    let template = findRawTemplate("list/custom-topic-list-item");
    if (user_id % 2 === 0)
       template = findRawTemplate("list/variant-custom-topic-list-item");
    if (template) {
      this.set("topicListItemContents", template(this).htmlSafe());
    }
  },
});

Danke

Beachten Sie, dass dies bei nicht angemeldeten Benutzern wahrscheinlich zu einem nicht abgefangenen Fehler führt. Ich empfehle, dies wie folgt zu ändern:

const user = api.getCurrentUser();
if (!user) return;

const userId = user.id;

Nachdem das geklärt ist, kommen wir zurück zu Ihrer Frage.

Im Gegensatz zu CSS unterstützt SCSS einen Eltern-Selektor, den Sie verwenden können.

Da Sie dies auf jeden zweiten Benutzer anwenden möchten (id % 2),

können Sie dies beim Laden der App überprüfen. Also etwas wie dies ganz oben:

const user = api.getCurrentUser();
const userId = user.id;

if (!userId) return;

const testThemeUser = userId % 2 === 0;

if (testThemeUser) {
  document.body.classList.add("test-theme");
}

Anschließend können Sie testThemeUser in Ihren JS-Bedingungen und die CSS-Klasse test-theme in Ihren Styles verwenden.

Also etwas wie dies.

JS

let template = findRawTemplate("list/custom-topic-list-item");
if (testThemeUser)
  template = findRawTemplate("list/variant-custom-topic-list-item");
if (template) {
  this.set("topicListItemContents", template(this).htmlSafe());
}

SCSS

.topic-list {
  tbody {
    border: none;
  }
  tr {
    border: none;
  }
  .example-div {
    border: none;
  }
  // test-theme SCSS
  .test-theme & {
    .example-div {
      border: 2px solid black;
    }
    .another-example-div {
      font-size: 10px;
    }
  }
}

Danke für deine Antwort @Johani
Derzeit muss ich nur eine bestimmte Komponentenklasse aktualisieren, und zwar die topic-list, daher verwende ich diesen Ansatz:

const useTestTheme = userId % 2 === 0

api.modifyClass('component:topic-list', {
    classNameBindings: ["test"],
    test: useTestTheme,
})