Wie löse ich das Problem mit dem Bildaustausch (hover, etc.)?

1 Antwort

Vom Beitragsersteller als hilfreich ausgezeichnet

Für die :visited-Pseudoklasse werden nur bestimmte CSS-Properties unterstützt. Das Setzen eines Hintergrundbildes gehört nicht dazu (lies dazu hier; eine ausführlichere Erklärung hat Mozilla schon einmal in diesem Artikel abgegeben).

Eine Ausweichmöglichkeit wäre eine Lösung via JavaScript. Bei Klick auf den Link wird ein Cookie gesetzt. Bei Aufruf der Seite wiederum wird geprüft, ob der Cookie existiert. Wenn ja, setzt du eine CSS-Klasse auf dem Element, welche das richtige Hintergrundbild definiert.

Beispiel:

const link = document.querySelector(".img-link");

if (getCookie("link-visited")) {
  link.classList.add("img-link--visited");
}

link.addEventListener("click", () => {
  setCookie("link-visited", 1, 31);
});

Für das Setzen/Lesen des Cookies kannst du die Funktionen aus diesem W3Schools-Artikel nutzen. Alternativ zu einem Cookie könnte man ebenso den Web Storage verwenden.

Zuletzt noch ein Hinweis bezüglich der Reihenfolge deiner anderen CSS-Selektoren: Der Selektor mit der Pseudoklasse :focus überschreibt den Selektor mit :active. Daher solltest du deren Reihenfolge austauschen.


fx8350 
Beitragsersteller
 17.01.2024, 13:59

Hi,

ich wollte das gerade mal probieren mit dem Java Skript, damit kenne ich mich jedoch nicht aus. Jedenfalls habe ich den Code in ein eigenes Javascript-Dokument kopiert und bei der Seite im head eingebunden, aber da passiert nichts, also ein cookie wird nicht gesetzt. Kannst du mir das ggf. etwas genauer erklären?

Die von dir verlinkte Seite hat mir da nicht geholfen, da ich davon nur Bahnhof verstehe. Bisher hatte ich keinen Kontakt zu Javascript.

Danke.

0
regex9  17.01.2024, 18:32
@fx8350

Füge zuerst deinem script-Element ein defer-Attribut hinzu, um sicherzustellen, dass das Skript erst ausgeführt wird, wenn alle Seitenelemente (wie deine Links) geladen wurden.

<script defer src="path/to/script.js"></script>

Auf der W3Schools-Seite findest du zwei Funktionen (set-/getCookie; unter All Together Now), die du deinem Skript noch zufügen musst.

Innerhalb deines CSS-Codes brauchst du des Weiteren noch einen Klassenselektor (.img-link--visited), welcher das Bild setzt.

Beim Testen musst du berücksichtigen, dass das Setzen des Cookies nur klappen wird, wenn dein HTML-Dokument über einen Webserver ausgespielt wird. Solltest du das Dokument lokal auf deinem Rechner öffnen (über das file:///-Protokoll, siehe Adresszeile), wird dein Browser das Setzen eines Cookies blockieren. Abhilfe würde die Einrichtung eines Webservers auf dem eigenen Rechner schaffen, bspw. mittels des XAMPP-Softwarepakets (Kurzanleitung; statt PHP- agierst du natürlich mit deinen HTML-Dateien, den Apache Server startest du via XAMPP Control Panel).

0
fx8350 
Beitragsersteller
 17.01.2024, 19:34
@regex9

Hi,

wie gesagt, ich verstehe das nicht. Natürlich verstehe ich, dass ich einen Cookie setzen muss, aber ich verstehe den Inhalt und die ganzen Funktionen im Code nicht. Unter anderem verstehe ich nicht, wie ich aus einem gesetzten Cookie nach der Beschreibung nun auf den Cookie mit dem Namen "link-visited" verweisen muss. Denn so wie ich das sehe, hat der gesetzte Cookie überhaupt keine Verbindung zu dem Namen.

Ich müsste also einen Cookie setzen mit dem Namen "link-visited"? Und was soll dann der Code von W3Schools damit zu tun haben?

function setCookie(cname, cvalue, exdays) {
  const d = new Date();
  d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
  let expires = "expires="+d.toUTCString();
  document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}


function getCookie(cname) {
  let name = cname + "=";
  let ca = document.cookie.split(';');
  for(let i = 0; i < ca.length; i++) {
    let c = ca[i];
    while (c.charAt(0) == ' ') {
      c = c.substring(1);
    }
    if (c.indexOf(name) == 0) {
      return c.substring(name.length, c.length);
    }
  }
  return "";
}


const link = document.querySelector(".img-link");


if (getCookie("link-visited")) {
  link.classList.add(".img-link:visited");
}


link.addEventListener("click", () => {
  setCookie("link-visited", 1, 31);
});

Die Klasse .img-link--visited gibt es nicht, aber ich hatte ja bereits die Klasse .img-link:visited, kann ich die nicht verwenden? Testen kann ich direkt online, das reicht mir. So wie oben passiert jedenfalls nichts.

0
regex9  17.01.2024, 20:28
@fx8350
(...) aber ich verstehe den Inhalt und die ganzen Funktionen im Code nicht.

Mein obiges Codesnippet sucht erst das Linkelement auf der Seite (erste Element mit der Klasse img-link). Dann prüft es, ob es den Cookie schon gibt und wenn ja, wird dem Linkelement eine weitere Klasse zugeordnet. Zuletzt wird dem Link noch ein Ereignishandler zugeordnet, der bei Klick auf den Link ausgeführt wird. Er setzt einen Cookie mit dem Wert 1 und einer Haltbarkeit von 31d.

Rein zur Nutzung sollten Code und Erklärung genügen, eine Anpassung von Ersterem ist von deiner Seite nicht notwendig (Beachte: Ich habe den Snippet in meiner Antwort eben nochmal bearbeitet). Wenn dir das aber dennoch nicht ausreicht, musst du dich doch erst mit JavaScript sowie der DOM-API auseinandersetzen. Gute Tutorials findest du dazu auf MediaEvent (JS Basis/Webseiten). Als grundsätzliche/s Nachschlagewerk/Referenz empfehle ich wiederum MDN.

Denn so wie ich das sehe, hat der gesetzte Cookie überhaupt keine Verbindung zu dem Namen.

Wie der Cookie heißt, ist unwichtig. Bei mir heißt er link-visited, doch er könnte genauso auch test123 heißen. Er dient nur als Flag/Schalter, der nach Linkklick (und darauffolgendem Neuladen der Seite) umgelegt wird. Anhand des Flagzustands lässt sich schließlich festmachen, ob er eine zusätzliche Klasse bekommen soll oder nicht.

Und was soll dann der Code von W3Schools damit zu tun haben?

Der liefert die Funktionalität, dass überhaupt ein Cookie gesetzt / gelesen werden kann.

(...) aber ich hatte ja bereits die Klasse .img-link:visited, kann ich die nicht verwenden? (...)

Nein. Das ist keine Klasse sondern eine Kombination aus verschiedenen CSS-Selektoren (Klassenselektor + Pseudoklasse).

1
fx8350 
Beitragsersteller
 18.01.2024, 13:07
@regex9

Danke für deine Mühen. An sich hatte ich nicht vor mir Java anzueignen, da ich nicht vorhabe es zu verwenden. Dies hat in diesem Fall nur optische Hintergründe, damit Textfarbe zu dem Bild passen. Wie ich jetzt noch den Code anpassen muss von W3School sowie das Thema mit der Klasse umsetze, verstehe ich nicht, das ist total Neuland.

Wenn es so kompliziert ist für ein Bild, dann muss ich es eben so lassen.

0
fx8350 
Beitragsersteller
 18.01.2024, 13:34
@fx8350

PS: Der Cookie wird jetzt gesetzt. Danke dafür.

0
regex9  18.01.2024, 15:06
@fx8350
An sich hatte ich nicht vor mir Java anzueignen, da ich nicht vorhabe es zu verwenden

JavaScript. 😉 Java ist nochmal eine völlig andere Sprache.

Wie ich jetzt noch den Code anpassen muss von W3School (...)

Gar nicht. Reinkopieren genügt, so wie du es in deinem obigen Kommentar bereits getan hast.

(...) sowie das Thema mit der Klasse umsetze (...)

Statt der CSS-Regel mit :visited brauchst du nun nur eine Regel mit dem entsprechenden Klassenselektor.

a.img-link--visited {
  /* css properties for link visited state ... */
}
1
fx8350 
Beitragsersteller
 18.01.2024, 15:11
@regex9

Dann habe ich es doch richtig verstanden. Allerdings funktioniert es nicht.

Wollte lediglich das Bild austauschen, aber hier passiert nichts.

a.img-link--visited {
  background: url(../img/li-button-yellow.png);
}
0
fx8350 
Beitragsersteller
 18.01.2024, 15:29
@fx8350

Mir fällt auch auf, dass es nur für einen Link geht.

Ich habe aber eine Linkliste, die alle die gleichen Bilder verwenden.
Scheint also nicht so einfach zu sein.

Habe aber überprüft ob denn die Klasse gesetzt wird. Dies ist der Fall, aber ob hier dann die Klasse ersetzt werden müsste, welche vorher da stand?

<a href="#" class="img-link img-link--visited" title="besuche mich auf Tiktok">Tiktok</a>  
0
regex9  19.01.2024, 09:13
@fx8350
Mir fällt auch auf, dass es nur für einen Link geht.

Ja, die Lösung ist nur für diesen einen Link. Das habe ich in einem der obigen Kommentare schon erwähnt.

Für mehrere Links müsste man mehr Informationen speichern. An sich reicht dafür immer noch der eine Cookie aus, aber er müsste sich in einer Liste merken, welche Links bereits angeklickt wurden. Um die Links zu identifizieren, würde ich jedem Link ein data-Attribut geben.

Beispiel:

<a class="img-link" data-id="1" href="...">Link 1</a>
<a class="img-link" data-id="2" href="...">Link 2</a>
<!-- etc. --->

Das Skript müsste natürlich verändert werden. Die Funktionen von W3Schools bleiben unberührt, alles andere wird ersetzt.

function getVisitedLinks(value) {
  let visitedLinks;

  try {
    visitedLinks = JSON.parse(getCookie("link-visited"));
  }
  catch (ex) {
  }

  return visitedLinks || {};
}

const links = document.querySelectorAll(".img-link");
const visitedLinks = getVisitedLinks(getCookie("link-visited"));

for (const link of links) {
  if (visitedLinks.hasOwnProperty(link.dataset.id)) {
    link.classList.add("img-link--visited");
  }

  link.addEventListener("click", () => {
    visitedLinks[link.dataset.id] = 1;
    setCookie("link-visited", JSON.stringify(visitedLinks), 31);
  });
}

Im Gegensatz zu zuvor speichert der Cookie nun ein JSON-Objekt. Besuchte Links werden als Properties dieses Objekts gespeichert. Dabei entspricht der Property-Name dem Wert des data-Attributs.

Außerdem werden nun alle Links berücksichtig, die eine img-link-Klasse haben.

Der alte Cookie muss im Browser übrigens gelöscht werden, andernfalls wird dieses neue Skript nicht funktionieren.

Habe aber überprüft ob denn die Klasse gesetzt wird. Dies ist der Fall, aber ob hier dann die Klasse ersetzt werden müsste, welche vorher da stand?

Der Selektor mit der Klasse img-link--visited wird bei dir eine geringere Spezifität als ein anderer Selektor haben, weshalb dieser nun überschrieben wird. Prüfe zuerst die Reihenfolge: Die neue CSS-Regel muss unter deinen bisherigen Regeln stehen. Wenn das nicht ausreicht, schau im Webinspektor deiner Browserentwicklungstools. Dort werden dir für das selektierte Element die einwirkenden CSS-Regeln aufgelistet. Die Reihenfolge zeigt an, welcher Selektor sich eher durchsetzt - also eine höhere Spezifität hat. Durchgestrichene CSS-Properties werden überschrieben.

1
fx8350 
Beitragsersteller
 18.02.2024, 13:15
@regex9

Hi, sorry dass ich mich jetzt nochmal hierzu melde. Ich habe es nun hinbekommen und noch zwei Probleme:

  1. Das Hintergrundbild wird nun entsprechend gesetzt, aber erst, nachdem die Seite neu geladen wurde. Gibt es eine Möglichkeit, dass genauso wie mit der Textfarbe, auch das Bild unverzüglich nach öffnen des Links getauscht wird? Mit active und focus geht es ja auch.
  2. Ich muss ja den Cookie löschen. Das kann ich ja nicht von den Besuchern der Seite erklären. Kann ich mittels Script den Cookie prüfen, ob er vor Datum XX.XX.XXXX und Uhrzeit XX:XX erstellt wurde (sofern vorhanden) und dann löschen und neu erstellen oder überschreiben lassen?

Danke sehr, du warst mir schon eine sehr große Hilfe.

0
regex9  18.02.2024, 21:32
@fx8350

1) Bei Klick kann die Klasse auch noch gesetzt werden:

link.addEventListener("click", () => {
  link.classList.add("img-link--visited"); // set class
  /* etc. ... */
});

2) Der Cookie hat ein bestimmtes Haltbarkeitsdatum, welches beim Anlegen (Aufruf von setCookie) gesetzt wird. Im obigen Code habe ich 31 Tage vorgegeben, du kannst aber auch eine andere Dauer definieren.

setCookie("link-visited", 1, 31);

Würde ein Nutzer nach 31 Tagen auf deine Seite kommen, würde der Browser den Cookie automatisch löschen, da dessen Haltbarkeit dann abgelaufen ist.

Für den Fall, dass der Cookie sofort (z.B. bei einem Buttonklick) gelöscht werden muss, dann setze ihn einfach nochmal, mit einem Datum in der Vergangenheit:

Beispiel:

setCookie("link-visited", 1, -1);

Nach erneutem Laden der Webseite würde der Browser den Cookie komplett entfernen.

1
fx8350 
Beitragsersteller
 17.01.2024, 08:38

Ok, danke. Wenn ich ein Cookie setze, müsste ich einen Cookie Consent einbauen, da man sich die Zustimmung holen muss, richtig?

Ich habe noch ein Problem, dass lediglich die Bildgröße unter link korrekt angezeigt wird. Bei :hover etc. In Originalgröße. Ich war der Meinung, dass es reicht, wenn ich das unter a:link definiere und dann auch für die anderen gilt.

Worunter müsste ich z. B. background-size: setzen, damit es für alle Bilder der Klasse angewendet wird?

Danke.

0
regex9  17.01.2024, 09:45
@fx8350

Du müsstest darauf hinweisen, dass Cookies verwendet werden (gilt ebenso, wenn du mit Web Storage arbeitest). Eine explizite Einwilligung benötigst du vermutlich nicht, da man diesen Cookie bestimmt auch zur Kategorie funktionaler Cookies zuordnen kann. Rechtssicherheit kann ich für diese letzte Aussage allerdings nicht übernehmen.

Du verwendest in deinen Sektoren ein Shorthand-Property (background). Mit dem können alle background-Properties (background-size, background-repeat, etc.) gesetzt werden, was wiederum auch bedeutet, dass du sie jedesmal allesamt überschreibst. Setze das Hintergrundbild in den CSS-Regeln stattdessen via background-image. Dann reicht es aus, background-size nur einmal in a.img-link oder a.img-link:link zu definieren.

Ich würde des Weiteren empfehlen, eine Hintergrundfarbe (background-color) festzulegen, die entsprechend der Schriftfarbe hell oder dunkel ist. Sollte das Laden des Bildes einmal länger dauern, wird die Hintergrundfarbe als Fallback angezeigt. Der Nutzer hat dadurch den Vorteil, trotzdem schon früh mit dem Link interagieren zu können, da bspw. der Linktitel von Anfang an lesbar ist.

1
fx8350 
Beitragsersteller
 17.01.2024, 10:54
@regex9

Ok, ich schaue mir das später an, kämpfe gerade mit Covid. Hatte nicht daran gedacht, dass ich eine Hintergrundfarbe extra für die Links benötige, wenn ich bereits eine für das body habe.

0
regex9  17.01.2024, 11:22
@fx8350

Wenn deine Bilder für die Links sich in der Helligkeit genauso verhalten, wie die Hintergrundfarbe der Seite / des Containers, in dem sich der Link befindet, brauchen die Links keine explizite Hintergrundfarbe. Mein Tipp zielte nur darauf ab, dass du zwischen Schriftfarbe und Hintergrund immer einen klaren Kontrast hast. 🙂

1
fx8350 
Beitragsersteller
 17.01.2024, 11:46
@regex9

Verstehe. Das Problem erübrigt sich deshalb, weil die Bilder png Format haben und es sich lediglich um gezeichnete und bearbeitete Rahmen handelt. Das heißt sie sind bis auf den Rahmen durchsichtig und werden ganz normal mittels a-tag beschriftet. Die Schrift ist also ohnehin da und kein Alternativ-Text.

0