HTML5-Tutorium: JavaScript: Hello World 06: Unterschied zwischen den Versionen

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg
Keine Bearbeitungszusammenfassung
(14 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
{{In Bearbeitung}}
{{HTML5-Tutorium:JavaScript:HelloWorld:Menü}}
{{HTML5-Tutorium:JavaScript:HelloWorld:Menü}}


'''Musterlösung''': [https://glossar.hs-augsburg.de/beispiel/tutorium/es5/hello_world/WK_HelloWorld05/web/index.html <code>index.html</code>],
'''Musterlösung''': [https://glossar.hs-augsburg.de/beispiel/tutorium/2021/hello_world/WK_HelloWorld06/web/index6.html <code>index6.html</code>]
([https://glossar.hs-augsburg.de/beispiel/tutorium/es6/hello_world/WK_HelloWorld05/ SVN-Repository])
([https://gitlab.multimedia.hs-augsburg.de/kowa/WK_HelloWorld06.git Git-Repository])
 
==Anwendungsfälle (Use Cases)==
==Anwendungsfälle (Use Cases)==
Gegenüber dem [[HTML5-Tutorium:_JavaScript:_Hello_World_04|vierten Teil des Tutoriums]]
Gegenüber dem [[HTML5-Tutorium:_JavaScript:_Hello_World_05|dritten Teil des Tutoriums]]
ändern sich die die Anwendungsfälle nicht.
ändern sich die die Anwendungsfälle nicht. Die Anwendung leistet also genau dasselbe wie zuvor.


In diesem und im nächsten Teil des Tutoriums werden zwei wesentliche [[Programmierprinzipien|Grundprinzipien der Programmierung]]
In diesem Teil des Tutoriums geht es darum, CSS durch SCSS zu ersetzen, um den CSS-Code „[[DRY]] zu machen“.
thematisiert:
* [[Don't repeat yourself]] (DRY,  “Keep your code DRY!”). 
* Konstanten gehören nicht in den Code, sondern in Konfigurationsdateien.


==Erstellen eines neuen Projektes==
==Erstellen eines neuen Projektes==


Erzeugen Sie wie im  [[HTML5-Tutorium:_JavaScript:_Hello_World_04|vierten Teil des Tutoriums]] ein neues Projekt,
Erstellen Sie ein neues Projekt <code>HelloWorld06</code> als Fork von <code>HelloWorld05</code> (siehe [[HTML5-Tutorium: JavaScript: Hello World 02|Hello-World-02-Tutorium]]).
diesmal allerdings mit dem schönen Namen <code>HelloWorld05</code>“ und speichern Sie dieses wieder
in Ihrem SVN-Repository (Achtung: <code>node_modules</code> muss existieren und auf der Ignore-Liste stehen).


Kopieren Sie nun aus Ihrer Lösung des vierten Teil des Tutoriums die Ordner <code>src</code> und <code>web</code>
<source lang="bash">
(jeweils samt allen darin enthaltenen Ordnern und Dateien) sowie die Dateien <code>gruntfile.js</code>,
git clone https://gitlab.multimedia.hs-augsburg.de/ACCOUNT/HelloWorld05 HelloWorld06
<code>package.json</code>, <code>package-lock.json</code> und <code>webpack.config.js</code>
//git clone https://gitlab.multimedia.hs-augsburg.de/kowa/WK_HelloWorld05d HelloWorld06
fügen Sie sie ins Wurzelverzeichnis des fünften Teils ein.
 
Weisen Sie WebStorm wiederum an, die Inhalte der Ordner <code>node_modules</code> und <code>web/js</code>
nicht auf Syntaxfehler zu überprüfen. Gegebenenfalls müssen Sie auch wieder die Dateien <code>gruntfile.js</code>
... <code>webpack.config.js</code> unter die Versionsverwaltung von SVN stellen (<code>Add to VCS</code>).


Ändern Sie in den Dateien <code>package.json</code> und <code>web/index.html</code> die Versionsnummern,
## Änderungen zur Projektidentifikation vornehmen (z.B. Titel anpassen)
die Beschreibung und gegebenenfalls den Pfad zum Repository Ihres Projektes.
git commit -m "HelloWorld05 fork created"


Zu guter Letzt öffnen Sie das WebStorm-Terminal und führen den Befehl <code>npm install</code>aus.
# Neues Repository in Gitlab anlegen:
Damit werden dieselben Node.js-Pakete installiert wie im vierten Teil des Tutoriums.
git remote -v
 
git remote remove origin
Löschen Sie die Datei <code>web/js/app.bundle.js</code> und
git remote add origin https://gitlab.multimedia.hs-augsburg.de/ACCOUNT/HelloWorld06
rufen Sie anschließend <code>grunt</code> auf, um diese Datei erneut zu erzeugen.
git remote -v
Wenn Sie jetzt die Datei <code>index.html</code> im Browser öffnen, sollte die
git push --set-upstream origin master
Web-Anwendung so wie in Teil 4 der Aufgabe funktionieren.
 
==Verfeinerung der Webpack-Umgebung==
Zunächst benötigen Sie ein paar weitere Node.js-Module
<source lang="bash">
npm install --save-dev es6-autobind
npm install --save-dev node-sass sass-loader extract-text-webpack-plugin
</source>
</source>


Im vierten Teil des Tutoriums wurde die Datei <code>initial.css</code> nicht von Webpack verwaltet,
==SCSS==
sondern direkt in das Verzeichnis <code>web/css</code> eingefügt. Damit liegt auch die
Verantwortung für die Komprimierung dieser Datei beim Programmierer. Das soll sich ändern.
Sie erweitern die Webpack-Konfiguration so, dass künftig auch diese Datei unter der Kontrolle
von Webpack steht.
 
===SCSS===


Anstelle von CSS-Dateien verwenden Sie künftig SCSS-Dateien. Das ist zunächst einmal nicht weiter schwer,
Anstelle von CSS-Dateien verwenden Sie künftig SCSS-Dateien. Das ist zunächst einmal nicht weiter schwer,
Zeile 58: Zeile 35:
allerdings das Prinzip  „[[Don't repeat yourself]]“ (DRY) nicht beachten. Sie müssen für verschiedene Elemente
allerdings das Prinzip  „[[Don't repeat yourself]]“ (DRY) nicht beachten. Sie müssen für verschiedene Elemente
ständig Informationen wiederholen (gewünschter Font, Hintergrundfarbe, Größenangaben etc.). Deshalb
ständig Informationen wiederholen (gewünschter Font, Hintergrundfarbe, Größenangaben etc.). Deshalb
gibt es mehrere Projekte wie {{zB}} [[LESS]] und [[Sass]] , die den CSS-Standard erweitern, um dieses Problem
gibt es mehrere Projekte wie {{zB}} [[LESS]], [[Sass]]/SCSS, [[Stylus]], die den CSS-Standard erweitern, um dieses Problem
zu vermeiden. Sass verwendet allerdings eine ganz andere Syntax als CSS. Allerdings
zu vermeiden. Sass verwendet allerdings eine ganz andere Syntax als CSS. Allerdings
unterstützt das Sass-Projekt auch die Sprache SCSS, die CSS einfach um weitere syntaktische Elemente ergänzt.  
unterstützt das Sass-Projekt auch die Sprache SCSS, die CSS einfach um weitere syntaktische Elemente ergänzt.  
Zeile 64: Zeile 41:


<source lang="CSS">
<source lang="CSS">
$background-color: #C5EFFC;
$background-color: #C5EFFC;
</source>
</source>


Und nun kann man in der CSS-Datei anstelle von <code>#C5EFFC</code> stets  <code>&#36;background-color</code>
Und nun kann man in eine SCSS-Datei anstelle von <code>#C5EFFC</code> stets  <code>&#36;background-color</code>
schreiben, um die Hintergrundfarbe von bestimmten Elementen zu definieren. Wenn man nun dieses Farbe ändern will,
schreiben, um die Hintergrundfarbe von bestimmten Elementen zu definieren. Wenn man nun diese Farbe ändern will,
muss das nicht mehr bei allen Elementen einzeln passieren. Es reicht, die Farbe in der Konstantendefinition abzuändern.
muss das nicht mehr bei allen Elementen einzeln passieren. Es reicht, die Farbe in der Konstantendefinition abzuändern.
Der CSS-Code ist nun DRY.
Der SCSS-Code ist nun DRY.


Leider unterstützt kein Browser SCSS direkt. Aber für was gibt es Transpiler wie Webpack, die eine SCSS-Datei  
Leider unterstützt kein Browser SCSS direkt. Aber für was gibt es Transpiler wie Webpack, die eine SCSS-Datei  
automatisch in eine CSS-Datei übersetzen können.
automatisch in eine CSS-Datei übersetzen können. Im [[HTML5-Tutorium: JavaScript: Hello World 05|fünften Teil des Hello-World-Tutorium]]
haben wir im der [https://gitlab.multimedia.hs-augsburg.de/kowa/WK_HelloWorld06.git Version 5d] den SASS-Loader verwendet,
um CSS-Dateien zu komprimieren. Damit haben wir aber gleichzeitig auch die Möglichkeit erhalten mit SCSS-Dateien an Stelle von CSS-Dateien zu verwenden.
 
Benennen Sie die Dateien <code>src/css/head.css</code> und <code>src/css/body.css</code> in
<code>src/css/head.scss</code> und <code>src/css/body.scss</code> um. Ersetzen Sie außerdem
in der Datei <code>src/js/main.js</code> den Import-Befehl
 
<source lang="javascript">
import '/css/body.css';
</source>
 
durch
 
<source lang="javascript">
import '/css/body.scss';
</source>
 
Zu guter Letzt müssen sie in <code>webpack.config.js</code> im Entry-Objekt folgende Ersetzung vornehmen:
 
<source lang="javascript">
head: absolutePath('src/css/head.css')
</source>
 
wird zu
 
<source lang="javascript">
head: absolutePath('src/css/head.scss')
</source>
 
Wenn Sie nun mittels <code>npm run dev</code> oder <code>npm run prod</code> Ihren Code übersetzen,
sollte noch alle laufen, da der SASS-Loader die neuen SCCS-Dateien ebenfalls in CSS-Dateien übersetzt.


Ersetzen Sie in Ihrem Projekt die Datei <code>src/css/main.css</code> durch  
Ersetzen Sie in Ihrem Projekt die Datei <code>src/css/main.css</code> durch  
drei SCSS-Dateien: <code>_config.scss</code>, <code>initial.scss</code> und </code>app.scss</code>.
drei SCSS-Dateien: <code>_config.scss</code>, <code>initial.scss</code> und </code>app.scss</code>.
===SCSS-Konfiguration===


In der Datei <code>_config.scss</code> werden alle von den anderen SCSS-Dateien benötigten Konstanten definiert.
In der Datei <code>_config.scss</code> werden alle von den anderen SCSS-Dateien benötigten Konstanten definiert.
Das heißt, das Prinzip „Konstanten gehören nicht in den Code, sondern in Konfigurationsdateien“ wird ab sofort beachtet.
Das heißt, das DRY-Prinzip „Konstanten gehören nicht in den Code, sondern in Konfigurationsdateien“ wird ab sofort beachtet.
Wenn man künftig am Layout einen Zeichensatz, eine Farbe, einen Hintergrund oder Ähnliches ändern will,  
Wenn man künftig am Layout einen Zeichensatz, eine Farbe, einen Hintergrund oder Ähnliches ändern will,  
reicht es, die entsprechenden Konstanten anzupassen und schon erzeugt Webpack automatisch aktualisiere
reicht es, die entsprechenden Konstanten anzupassen und schon erzeugt Webpack automatisch aktualisiere
CSS-Dateien.
CSS-Dateien.


Die Datei <code>initial.scss</code> enthält möglichst wenig Code. Das ist Vorlage für die Datei <code>initial.bundle.css</code>,
Der Underscore <code>_</code> am Beginn des Dateinamens deutet an, dass diese SCSS-Datei nur von anderen SCSS-Dateien
die im HTML-Head-Bereich geladen vor dem Body-Inhalt werden soll.
aber nicht von HTML- oder JavaScript-Dateien importiert werden. Durch SCSS-Import-Befehle ist es möglich, auch SCSS-Dateien
Die eigentlichen CSS-Informationen der Web-Anwendung werden in <code>app.scss</code> gespeichert. Die zugehörigen
zu modularisieren.
CSS-Anweisungen werden von Webpack wie gehabt in <code>app.bundle.js</code> integriert.


'''<code>src/css/_config.scss</code>'''
'''<code>src/css/_config.scss</code>'''
<source lang="CSS">
<source lang="CSS">
@use 'sass:math';
$background-color:  #C5EFFC;
$font-family-sans:  Verdana, Helvetica, sans-serif;
$font-family-sans:  Verdana, Helvetica, sans-serif;
$font-family-serif: "Times New Roman", Times, serif;
$font-family-serif: "Times New Roman", Times, serif;
$background-color#C5EFFC;
 
$font-size-base:    3vw;
$font-size-factor:  1.25;  // cmp. https://type-scale.com/
   
$font-size-h5:      math.pow($font-size-factor,1)*$font-size-base;
$font-size-h4:      math.pow($font-size-factor,2)*$font-size-base;
$font-size-h3:      math.pow($font-size-factor,3)*$font-size-base;
$font-size-h2:      math.pow($font-size-factor,4)*$font-size-base;
$font-size-h1:      math.pow($font-size-factor,5)*$font-size-base;
 
$font-size-p:      math.pow($font-size-factor,0)*$font-size-base;
$font-size-p-large: math.pow($font-size-factor,2)*$font-size-base;
 
$font-size-small:  math.pow($font-size-factor,-1)*$font-size-base;
</source>
</source>


Diese Datei kann nun mit Hilfe des SCSS-Befehls <code>@import</code>  
Konstanten starten in SCSS mit einem Dollarzeichen. Sobald eine Konstante definiert wurde,
in die anderen beiden SCSS-Dateien eingefügt werden. Webpack (genauer gesagt das SASS-Modul von Webpack)
kann sie in allen weiteren SCSS-Konstrukten verwendet werden. In SCSS stehen einen Operatoren zur Verfügung wie
<code>+</code>, <code>-</code>, <code>*</code> und <code>/</code>, um Maße zu berechnen. Es gibt
weitere Operatoren zum Vergleichen von Zahlen und Maßen sowie zur Berechnung von Strings und booleschen Werten:
https://sass-lang.com/documentation/operators.<ref>https://sass-lang.com/documentation/operators</ref>
 
Die Datei <code>_config.scss</code> kann nun mit Hilfe des SCSS-Befehls <code>@import 'config';</code> (ohne Underscore und ohne Endung)
in die anderen beiden SCSS-Dateien eingefügt werden. Webpack (genauer gesagt der SASS-Loader von Webpack)
kennt diesen Befehl und führt im beim Erstellen der zugehörigen CSS-Dateien auch aus.
kennt diesen Befehl und führt im beim Erstellen der zugehörigen CSS-Dateien auch aus.


Der Import-Befehl ist hier notwendig, da in der Datei <code>initial.scss</code> die Konstante <code>&#36;background-color</code>
Der Import-Befehl hat erst dann einen Effekt, wenn in den anderen Dateien auf diese Konstanten zugegriffen wird.
verwendet wird. Ansonsten enthält dies Datei nur den schon bekannten CSS-Code.
Aber er schadet auch nicht, wenn auf keine der dort definierten Konstanten zugegriffen wird. Der Import-Befehl selbst
taucht ebenso wenig in den generierten CSS-Dateien auf, wie die Konstantendefinitionen. Der Transpiler ersetzt Konstanten
in CSS-Definitionen durch ihren jeweiligen Wert.
 
Sie können nun beispielsweise in der Datei <code>head.scss</code> die Konstante <code>&#36;background-color</code>
verwenden. In der daraus erzeugten CSS-Datei steht weiterhin der Farbwert <code>#C5EFFC</code>;


'''<code>src/css/initial.scss</code>'''
'''<code>src/css/head.scss</code>'''
<source lang="CSS">
<source lang="CSS">
@import 'config';
@import 'config';


body
body
{ background-color: $background-color;
{ background-color: $background-color; }
}


.hidden
.hidden
{ display: none;
{ display: none; }
}
</source>
</source>


Die Datei <code>app.scss</code> ist deutlich umfangreicher. Daher soll der zugehörige CSS-Code
Die Datei <code>body.scss</code> ist deutlich umfangreicher. Daher wird der zugehörige CSS-Code
ja auch erst gemeinsam mit der Datei  <code>app.bundle.js</code> geladen werden. Das meiste ist üblicher
ja auch erst gemeinsam mit der Datei  <code>web/js/main.js</code> geladen.  
CSS-Code, den Sie schon im vierten Teil des Tutoriums kennengelernt haben. Es gibt ein paar neue
Elemente, wie die CSS-Klassen-Elemente <code>.left</code> und <code>.right</code>, die in der HTML-Datei dieses
Tutoriums zusätzlich verwendet werden. Außerdem sehen Sie in der Datei noch ein  paar weitere SCSS-Elemente. Diese werden
im Anschluss an den folgenden code beschrieben.


'''<code>src/css/app.scss</code>'''
'''<code>src/css/body.scss</code>'''
<source lang="CSS">
<source lang="CSS">
@import 'config';
@import 'config';
html, body
{ height:          100%;
  font-size:        2vw !important;
  font-family:      $font-family-sans;
  background-color: $background-color;
}


html
html
{ display: table;
{ height: 100%;
   width:  100%;
   width:  100%;
  display: table;
}
}


Zeile 143: Zeile 168:
   text-align:      center;
   text-align:      center;
   vertical-align:  middle;
   vertical-align:  middle;
  background-color: $background-color;
  font-size:        $font-size-base !important;
  font-family:      $font-family-sans;
}
}


h1
h1
{ padding-bottom: 0;
{ padding:   0;
   margin-bottom: 0;
   margin:   0;
}
   font-size: $font-size-h1;
 
#section_form
{ text-align:   center;
  width:        21em;
  margin-left: auto;
  margin-right: auto;
 
  h1
  { font-size:    200%;
    margin-bottom: 0.5ex;
  }
}
 
#section_hello
{ h1
  { font-size: 270%;
  }
}
}


p, label
p, label
{ font-family: $font-family-serif;
{ font-family: $font-family-serif;
   font-size:  100%;
   font-size:  $font-size-p !important;
}
}


label, input, button
label, input, button
{ width:         10em;
{ width:     10em;
   font-size:     100%;
   font-size: 100%;
   display:       inline-block;
   display:   inline-block;
   box-sizing:   border-box;
   box-sizing: border-box;
   margin-bottom: 0.5ex;
   margin:     0.5ex;
}
}


Zeile 185: Zeile 196:
}
}


@mixin panel()
#section_form
{ padding: 0;
{ text-align:   center;
   width50%;
  margin-left:  auto;
   margin-right: auto;
 
  h1
   { margin-bottom: 0.5ex; }
}
}


.left
#section_hello
{ float: left;
{ p
   @include panel();
   { font-size: $font-size-p-large !important; }
}
.right
{ float: right;
  @include panel();
}
}
</source>
</source>


In diese SCSS-Datei werden folgende SCSS-Erweiterungen verwendet:
In dieser SCSS-Datei werden folgende SCSS-Erweiterungen verwendet:


* Mathematische Berechnungen: <code>@use 'sass:math';</code>
* Import-Befehl: <code>@import 'config';</code>
* Import-Befehl: <code>@import 'config';</code>
* Konstanten:  <code>&#36;font-family-sans</code>, <code>&#36;font-family-serif</code>,  <code>&#36;background-color</code>
* Konstanten:  <code>&#36;font-family-sans</code>, <code>&#36;font-size-base</code> etc.
* Verschachtelte Anweisungen: {{zB}} <code>h1</code> innerhalb von  <code>#section_form</code>
* Verschachtelte Anweisungen: {{zB}} <code>h1</code> innerhalb von  <code>#section_form</code>
* Mixins, um eine Liste von Attributen nur einmal zu definieren und und mehreren Elemente wieder verwenden zu können.


Die verschachtelten Anweisungen strukturieren den CSS-Code deutlich besser. Es ist nicht mehr
Die verschachtelten Anweisungen strukturieren den CSS-Code deutlich besser. Es ist nicht mehr
notwendig einen Selektor wie <code>#section_form</code> mehrfach zu verwenden.
notwendig einen Selektor wie <code>#section_form</code> mehrfach zu verwenden.


Sehen Sie sich den Unterschied an. In der Datei <code>main.css</code> vom vierten Teil des Tutoriums hatten Sie
Sehen Sie sich den Unterschied an. In der Datei <code>src/css/body.css</code> der Musterlösungen vom dritten  Teil des Tutoriums hatte ich
folgendes geschrieben:
Folgendes geschrieben:


<source lang="CSS">
<source lang="CSS">
#section_form
#section_form
{
{ text-align:  center;
  text-align:  center;
  width:        21em;
   margin-left:  auto;
   margin-left:  auto;
   margin-right: auto;
   margin-right: auto;
Zeile 223: Zeile 232:


#section_form > h1
#section_form > h1
{
{ margin-bottom: 0.5ex; }
  font-size:    200%;
  margin-bottom: 0.5ex;
}
</source>
</source>


Zeile 234: Zeile 240:
#section_form
#section_form
{ text-align:  center;
{ text-align:  center;
  width:        21em;
   margin-left:  auto;
   margin-left:  auto;
   margin-right: auto;
   margin-right: auto;


   h1
   h1
   { font-size:    200%;
   { margin-bottom: 0.5ex; }
    margin-bottom: 0.5ex;
  }
}
}
</source>
</source>
Zeile 247: Zeile 250:
Insbesondere bei großen CSS-Dateien erweist sich diese kompaktere Schreibweise als vorteilhaft.
Insbesondere bei großen CSS-Dateien erweist sich diese kompaktere Schreibweise als vorteilhaft.


Ein weiteres Element, das nur SCSS bietet sind die Mixins. Sie definieren zunächst ein Mixin,
===Weitere SCSS-Konstrukte===
das eine Folge von CSS-Attributen zusammenfasst. (Auch hier könnten wieder Verschachtelungen und
andere SCSS-Erweiterungen verwendet werden!)
 
<source lang="CSS">
@mixin panel()
{ padding: 0;
  width:  50%;
}
</source>
 
Und nun können Sie dieses Mixin in diversen andere Elemente einbinden:
 
<source lang="CSS">
.left
{ float: left;
  @include panel();
 
.right
{ float: right;
  @include panel();
}
</source>
 
In normalen CSS-Code, müssten Sie denselben Code Non-DRY formulieren:
 
<source lang="CSS">
.left
{ float:  left;
  padding: 0;
  width:  50%;
}
 
.right
{ float:  right;
  padding: 0;
  width:  50%;
}
</source>
 
Wenn Sie hier das Layout der Panels ändern wollten (andere Breite, andere Ränder etc.), müssen
Sie den CSS-Code von jedem Panel einzeln ändern. In der SCSS-Datei erfolgt die Änderung dagegen DRY: Sie ändern einfach den Mixin-Code ab. 
 
Wenn die aktuellen Browser SCSS verstehen würden, könnte sie <code>initial.scss</code> und <code>app.scss</code> direkt
vom HTML-Code aus laden. Allerdings geht das derzeit leider nicht. Somit muss Webpack angewiesen werden, CSS-Code aus den
SCSS-Dateien zu erzeugen. Dies ist mit den beiden Node.js-Modulen <code>node-sass</code> und <code>sass-loader</code>,
die Sie bereits installiert haben, ganz einfach möglich.
 
Ersetzen Sie in der Datei <code>webpack.config.js</code> folgenden Code
 
<source lang="javascript">
{ test:  /\.css$/,
  use:    [ 'style-loader',
            { loader: 'css-loader', options: { minimize: true } }
          ]
},
</source>
 
durch folgenden:
 
<source lang="javascript">
{ test:  /\.(css|scss|sass)$/,
  use:    [ 'style-loader',
            { loader: 'css-loader', options: { minimize: true } },
            'sass-loader'
          ]
}
</source>
 
Der Test wird so erweitert, dass diese Regel jetzt nicht nur für die Verarbeitung von Dateien mit der
Endung <code>.css</code> zuständig ist, sondern auch für Dateien mit den Endungen
<code>.sass</code> und <code>.scss</code>.
 
Die Liste der zugehörigen Loader wird einfach um einen Loader erweitert:  <code>sass-loader</code>.
Diese Liste wird von hinten nach vorne abgearbeitet. Das heißt, eine Datei wie beispielsweise <code>app.scss</code>
wird erst mit Hilfe des Sass-Loaders in eine CSS-Datei umgewandelt, diese wird mit Hilfe des CSS-Loaders komprimiert
und das Ergebnis dieser Datei wird mit Hilfe des Style-Loaders in die zugehörige JavaScript-Ausgabedatei integriert.
 
Jetzt müssen nur noch die zugehörigen JavaScript-Dateien erstellt werden.
 
Im <code>entry</code>-Objekt der Datei <code>webpack.config.js</code> ist bereits die Datei <code>src/js/app.js</code>
eingetragen. Für Sie wird von Webpack die Datei <code>web/js/app.bundle.js</code> erzeugt.
 
Der Name der Zieldatei wurde im <code>output</code>-Objekt von <code>webpack.config.js</code> spezifiziert.
'''Achtung:''' Überprüfen Sie, ob das <code>output</code>-Objekt folgendermaßen definiert wurde.
 
<source lang="javascript">
  output:
  { filename: 'js/[name].bundle.js',
    path:    absolutePath('web')
  }
</source>
 
Damit diese Zieldatei insbesondere den komprimierten Code der Datei <code>src/css/app.scss</code> enthält,
muss <code>src/js/app.js</code> leicht modifiziert werden.
 
Ersetzen Sie in dieser Datei den Import-Befehl
 
<source lang="javascript">
import '../css/main.css';
</source>
durch den Import-Befehl
 
<source lang="javascript">
import '../css/app.scss';
</source>
 
Die Datei <code>web/css/main.css</code> gibt es ja nicht mehr; sie wurde durch
<code>web/css/app.scss</code> ersetzt.
 
Damit auch <code>web/css/initial.scss</code> durch webpack verwaltet wird, benötigen wir eine zweite
JavaScript-Datei.
 
'''src/js/initial.js'''
<source lang="javascript">
import '../css/initial.scss';
</source>
 
Sie sehen das richtig, die Datei <code>src/js/initial.js</code> enthält eine einzige Code-Zeile.
Sie erinnern sich? Webpack dient eigentlich nur dazu JavaScript-Dateien zu packen. Also geben wir diesen
Tool eine JavaScript-Datei, die die gewünschte CSS-Datei einfach mittels eine ES6-Import-Befehls importiert (ES6 = EcmaScript 6).
Fügen Sie nun in das <code>entry</code>-Objekt der Datei <code>webpack.config.js</code> vor der Zeile
 
<source lang="javascript">
app: absolutePath('src/js/app.js')
</source>
folgende zweite Zeile ein:
 
<source lang="javascript">
initial: absolutePath('src/js/initial.js')
</source>
 
Beachten Sie, dass in einem JavaScript-Objekt die Attribute durch Kommas voneinander getrennt werden. Fügen Sie also
an passender Stelle auch noch ein Komma ein.
 
Wenn Sie jetzt Grunt aufrufen, sollten zwei Dateien generiert werden: <code>web/js/app.bundle.js</code> und  <code>web/js/initial.bundle.js</code>.
 
Löschen Sie nun den Ordner <code>web/css</code> (die darin befindliche Datei <code>initial.css</code> wird nicht mehr benötigt)
und ersetzen Sie in der Datei <code>index.html</code> die Zeile
 
<source lang="html">
<link rel = "stylesheet" type = "text/css" href = "css/initial.css"/>
</source>
 
durch folgende Zeile:
 
<source lang="html">
<script type = "text/javascript" src = "js/initial.bundle.js"></script>
</source>
 
Wenn Sie jetzt die Datei <code>index.html</code> im Browser öffnen, sollte sie wieder genauso funktionieren wie zuvor.
 
'''Anmerkung''': Die Datei <code>src/js/initial.js</code> könnte natürlich noch mehr machen, als einfach nur eine CSS-Datei zu laden.
Sie könnte beispielsweise eine kleine Animation einblenden (die berühmte Sanduhr, nur etwas moderner), die solange läuft, bis
die eigentliche Web-Anwendung, {{dh}}  <code>app.bundle.js</code> vollständig geladen wurde und die Animation wieder beendet.
 
===Erzeugen einer CSS-Datei===
 
Zurzeit enthält die JavaScript-Datei <code>web/js/initial.bundle.js</code> nur eine komprimierte CSS-Datei und etwas Code,
um diesen in das HTML-Dokument einzufügen. Die Google-Suche bewertet HTML-Dateien, die sauberen CSS-Code {{iAllg}} enthalten,
höher, als HTML-Datei, die nur JavaScript-Code enthalten. Daher wäre es in diesem Fall sinnvoll, die komprimierte
CSS-Datei direkt in den HTML-Code einzubinden. Das ist aber gar nicht so einfach, da Webpack keine CSS-Dateien erstellt,
sondern nur JavaScript-Dateien. Aber mit einem kleine Hack funktioniert das trotzdem.
 
Sie haben vor auch noch die Node.js-Module <code>extract-text-webpack-plugin</code>
installiert. Mit diesem Sie eine CSS-Datei aus einer JavaScript-Datei extrahieren.
 
Ersetzen Sie zunächst in der Datei <code>webpack.config.js</code> den Test
<source lang="javascript">
test:  /\.(css|scss|sass)$/,
</source>
durch
<source lang="javascript">
test:  /app\.(css|scss|sass)$/,
</source>
 
Damit erreichen Sie dass diese Regel jetzt nur noch für Dateien funktioniert, die auf <code>app.css</code> oder
<code>app.scss</code> oder <code>app.sass</code> enden. Die Datei <code>src/css/app.scss</code> in die
Datei <code>src/js/app.bundle.js</code> integriert werden.
 
Laden Sie zunächst die ExtractTextPlugin-Erweiterung, indem Sie in die Datei <code>webpack.config.js</code>
folgende zweite Zeile einfügen:
<source lang="javascript">
const ExtractTextPlugin = require('extract-text-webpack-plugin');
</source>
 
Für die Datei <code>src/css/initial.scss</code> fügen Sie nun in die Liste mit den Regeln eine weitere Regel  ein (Komma nicht vergessen):
<source lang="javascript">
{ test:  /initial\.(css|scss|sass)$/,
  use:  ExtractTextPlugin.extract
        ({fallback: "style-loader",
          use:      [{ loader: 'css-loader', options: { minimize: true } },
                      'sass-loader'
                    ]
        })
}
</source>
 
Diese benutzt das zuvor erwähnte Plugin, um die komprimierte CSS-Datei aus der Datei <code>src/js/initial.bundle.js</code>
zu extrahieren. Das erledigt sie aber nur fast. Man muss dem Plugin noch mitteilen wohin Sie die CSS-Datei speichern soll.
 
Dazu müssen Sie die bislang leere Plugin-Liste am Ende der Datei
 
<source lang="javascript">
plugins:
[]
</source>
 
mit Inhalt füllen:
 
<source lang="javascript">
plugins:
[ new ExtractTextPlugin("css/[name].bundle.css") ]
</source>
 
Führen Sie nun <code>grunt</code> aus. Es sollte die Datei <code>web/css/initial.bundle.css</code>
erzeugt worden sein.
 
Nun müssen sie in der Datei <code>index.html</code> die Zeile
 
<source lang="html">
<script type = "text/javascript" src = "js/initial.bundle.js"></script>
 
</source>
 
wieder durch eine CSS-Link-Zeile ersetzen (da ja in der Datei <code>initial.bundle.js</code> kein sinnvoller Inhalt mehr enthalten ist;
sie wurde durch das Extract-Text-Plugin  „ausgelutscht“).
 
<source lang="html">
<link rel = "stylesheet" type = "text/css" href = "css/initial.bundle.css"/>
</source>
 
Sie könnten nun noch die überflüssige Datei <code>web/js/initial.bundle.js</code> von webpack wieder entfernen lassen.
Wie das geht entnehmen Sie bitte der Seite https://stackoverflow.com/questions/37408873/delete-or-not-create-a-file-for-each-entry-in-webpack
sowie der [https://glossar.hs-augsburg.de/beispiel/tutorium/es6/hello_world/WK_HelloWorld05/ Musterlösung]. Wichtig ist das nicht.
Wenn Sie später mal eine kleine Warteanimation erstellen sollten, bräuchten Sie dieses Datei sowieso wieder.
 
==JSON==
 
Bislang haben sie den CSS-Code unter Webpack-Kontrolle gestellt und damit DRY gemacht.
Als nächstes gehen wir das nächste Problem an: Ihr Code enthält ebenfalls Konstanten und verstößt damit gegen das
[[Programmierprinzipien|Programmierprinzip]] „Konstante Werte gehören nicht in den Code, sondern in Konfigurationsdateien.“
 
Eine Ausnahme bilden triviale Konstanten wie <code>0</code>, <code>1</code>, <code>null</code>, <code>true</code> oder <code>false</code>, sofern sie mit großer Sicherheit nie im Code geändert werden müssen. Aber schon eine Konstante wie
<code>3.1415926</code> gehört nicht in den Code. Man verwendet stattdessen besser <code>Math.PI</code> und erhält damit
die maximal mögliche Stellenzahl. (Eventuell hängt diese von der Rechnerplattform ab.)
 
In JavaScript-Anwendungen verwendet man [[JSON]] zur Speicherung von (konstanten) Daten und zur Initialisierung der Anwendung.
Wenn ein Spiel mehrere Level hat, wir jedes Level üblicherweise in einer eigenen JSON-Datei beschrieben. Eine Level-Designerin muss
im Optimalfall nicht mehr machen, als die Assets (Grafiken, Töne, 3D-Modell etc.) zu erstellen und mit Hilfe einer
JSON-Datei die Zusammenhänge zwischen den einzelnen Elementen herstellen. Es sollte nicht notwendig sein, dass sie
den Programmcode modifizieren muss, da das Level-Design schon aufwändig genug ist.
 
JSON (JavaScript Object Notation) ist ein einfaches Datenformat, mit dessen Hilfe sich komplexe Objekte sehr einfach beschreiben lassen.
Eine Alternative wäre [[XML]], allerdings ist diese Auszeichnungsprache deutlich komplexer. (Ein Beispiel für XML ist
XHMLT 1.0<ref>XHTML 1.0: https://www.w3.org/TR/2002/REC-xhtml1-20020801/</ref>, eine HTML-Variante.)
 
Eine JSON-Datei ist im Prinzip eine JavaScript-Datei, die einen der folgenden Datentypen enthält<ref>http://www.json.org/json-de.html</ref>:
 
* Nullwert (<code>null</code>)
* Boolescher Wert (<code>true</code> oder <code>false</code>)
* Zahl (Ziffernfolge mit optionalem Vorzeichen und optionalen Exponenten)
* Zeichenkette (beliebige UTF-8-Zeichen, die in doppelten geraden Anführungszeichen (<code>"</code>) eingeschlossen sind)
* Array (eine durch Kommata getrennte Listen von null oder mehr JSON-Elementen; die Liste beginnt mit <code>[</code> und endet mit <code>]</code>)
* Objekt/Hasharray/Paarliste (eine durch Kommata getrennte Listen von null oder mehr Paaren; die Liste beginnt mit <code>{</code> und endet mit <code>}</code>; jedes Paar besteht aus einer Zeichenketten, die als Schlüssel fungiert, gefolgt von einem Doppelpunkt  (<code>:</code>) gefolgt von einem beliebigen JSON-Element; in einem Objekt darf derselbe Schlüsselwert nicht zweimal vorkommen)
 
Beachten Sie, dass die eine [[Rekursion|rekursive]] Definition ist: Arrays dürfen andere Arrays und Objekte enthalten, Objekte dürfen
andere Objekte und Arrays enthalten. JSON-Elemente können also beliebig tief geschachtelt sein.
 
Andere Werte dürfen in einer JSON-Datei nicht enthalten sein. Das heißt, es gibt keine einfachen geraden Anführungszeichen (außer '''innerhalb''' von Zeichenketten), keine Kommentare, keine Funktionen etc. '''Insbesondere überflüssige Kommas sind nicht erlaubt!'''
 
Beachten Sie bitte, dass jeden JSON-Datei auch eine
JavaScript-Datei ist (die Umkehrung dieser aussage gilt nicht.). Wenn man eine JSON-Datei auswerten würde, erhielte man jedoch kein anderes Ergebnis als den Wert oder das Objekt, das in der Datei gespeichert ist.
 
Erstellen Sie in Ihrem Projekt  folgende zwei JSON-Dateien:
 
'''src/json/config_de.json'''
<source lang="javascript">
{
  "text":
  {
    "title":    "Hallo, Fremder!",
    "question": "Wie heißen Sie?",
    "reset":    "Reset",
    "submit":  "Begrüßung",
    "hello":    "Hallo, $1!",
    "welcome":  "Willkommen bei Multimedia-Programmierung!"
  },
 
  "css":
  {
    "hidden": "hidden"
  }
}
</source>
 
'''src/json/config_en.json'''
<source lang="javascript">
{
  "text":
  {
    "title":    "Hello, Stranger!",
    "question": "What's your name?",
    "reset":    "Reset",
    "submit":  "Say hello",
    "hello":    "Hello, $1!",
    "welcome":  "Welcome to Multimedia Programming!"
  },
 
  "css":
  {
    "hidden": "hidden"
  }
}
</source>
 
Importieren Sie die erste der beiden JSON-Dateien in Ihre Datei <code>src/js/app,js</code>,
indem Sie folgenden Import-Befehl einfügen:
<source lang="javascript">
import * as config from '../json/config_de.json';
</source>
 
In  <code>src/js/app/greet,js</code> fügen Sie folgenden
Import-Befehl ein:
<source lang="javascript">
import * as config from '../../json/config_de.json';
</source>
 
Beachten Sie, dass hier eine Zugriff auf das „Großvater“-Verzeichnis <code>src</code> mittel <code>../../</code> erfolgen muss.
Grundsätzlich sollten Sie in Import-Befehlen immer relative Pfadnamen angeben, da sonst eine Änderung der globalen Ordnerstruktur
zu massiven Problemen führen kann. Achten Sie bei Pfad-Angaben insbesondere auf Groß- und Kleinschreibung.
Gemeinerweise macht es auf Windows-Rechnern keinen Unterschied, ob sie in einem Pfadnamen Groß- oder Kleinbuchstaben
verwenden. Wenn Sie die Anwendung später auf einen Linux-Server kopieren, kommt es dann allerdings zu Problemen,
weil der Server die Pfade mit den falschen Groß- oder Kleinbuchstaben nicht mehr findet. Sie sollten in Dateinamen
am Besten überhaupt keine Großbuchstaben verwenden.
 
Wenn Sie jetzt <code>grunt</code> aufrufen und anschließend <code>index.html</code> im Browser öffnen,
hat sich noch nicht viel getan.
 
Ändern Sie nun den Inhalt der <code>index.html</code>. Löschen Sie alle englischen Text-Elemente.
sie sollten sie durch die angegebenen Dummy-Texte ersetzen, notwendig wäre das aber nicht:
 
* <code>Hello, Stranger!</code> → <code>TITLE</code>
* <code>What's your name?</code> → <code>QUESTION</code>
* <code>Reset</code> → <code>RESET</code>
* <code>Say hello</code> → <code>SUBMIT</code>
* <code>Hello, ...</code> → <code>HELLO</code>
* <code>Welcome to Multimedia Programming!</code> → <code>WELCOME</code>
 
Sie müssen außerdem noch einigen HTML-Tags zusätzlich ein <code>id</code>-Attribut zuordnen:
 
* H1-Element: <code>&lt;h1 id="heading_form"&gt;</code>
* Label-Element: <code>&lt;label id="input_label" ..&gt;</code>
* Reset-Button:  <code>&lt;input id="button_reset" type="reset" ...&gt;</code>
* Welcome-Paragraph: <code>&lt;p id="paragraph_hello">WELCOME&lt;/p&gt;</code>
 
Wenn Sie jetzt die <code>index.html</code> nochmals im Browser öffnen, sehen Sie nur noch die DUMMY-Texte.
 
Das ändert sich allerdings, wenn Sie folgende JavaScript-Befehle in die Datei <code>src/js/app.js</code> nach den
Import-Befehlen einfügen:
 
<source lang="javascript">
const c_config_text = config.text;
 
// Initialize the app.
document.getElementById('button_reset').value
  = c_config_text.reset;
document.getElementById('button_submit').value
  = c_config_text.submit;
 
document.getElementById('heading_form').innerHTML
  = c_config_text.title;
document.getElementById('input_label').innerHTML
  = c_config_text.question;
</source>
 
(Die restlichen Zeilen bleiben erhalten.)  Mit diesen fünf Befehlen speichern Sie den Inhalt des Attributs
<code>text</code> aus der eingelesenen JSON-Datei in der Konstanten
<code>c_config_text</code>. Anschließend ersetzen Sie mit Hilfe von vier weiteren Befehle
die Dummy-Texte im der Form-Section durch sinnvolle Texte.
 
Rufen Sie <code>grunt</code> auf und öffnen Sie anschließend <code>index.html</code> im Browser.
Jetzt sollten Sie deutsche Text an Stelle von Dummy-Texten sehen. Wenn Sie jetzt allerdings einen Namen eingeben
und auf den Begrüßungs-Button klicken, werden Sie englisch begrüßt und sehen einen weiteren Dummy-Text.
 
Das heißt, Sie müssen auch noch die Datei <code>src/js/app/greet.js</code> erweitern.
 
Ersetzen Sie in dieser Datei im Rumpf der Funktion <code>sayHello</code>
den darin enthalten Code durch folgenden Code:
 
<source lang="javascript">
const l_config_text = config.text,
      l_name      = document.getElementById("input_name").value;
 
document.getElementById('paragraph_hello').innerHTML
  = l_config_text.welcome;
document.getElementById('heading_hello').innerHTML
  = l_config_text.hello.replace('$1', l_name);
 
document.getElementById('section_hello')
  .classList.remove('hidden');
document.getElementById('section_form')
  .classList.add('hidden');
</source>


Die Funktion <code>sayHelloOnEnter</code> ändert sich dagegen nicht.
SCSS ist sehr nächtig. Es gibt neben der Import-Anweisung eine Use-Anweisung (<code>@use</code>)<ref>https://sass-lang.com/documentation/at-rules/use</ref>, die, SCSS-Konstrukten im Gegensatz zur Import-Anweisung einen Namespace zuweist. Damit ist es möglich mehrere SCSS-Module zu verwenden, auch wenn
dieses gleichbenannte Elemente enthalten, ohne dass es zu Namenskollisionen kommt.


Nun sollte (nach einen <code>grunt</code>-Lauf) die Web-App wie gewünscht funktionieren.
Darüber hinaus gibt es Mixins<ref>https://sass-lang.com/documentation/at-rules/mixin</ref> und Funktionen<ref>https://sass-lang.com/documentation/at-rules/function</ref>. Mit Mixins kann man ganze Styleblöcke definieren, um sie mehrfach zu verwenden. Mixins werden mit <code>@include</code> eingebunden. Dabei kann man Argumente an die Mixins übergeben, mit denen die entsprechenden Konstanten innerhalb des Mixins initialisiert werden. Funktionen funktionieren wie Funktionen in anderen Programmiersprachen auch. Es stehen einem If-Anweisungen und Schleifen-Befehle zur Verfügung.


Sie können jetzt testweise mal in beiden Dateien <code>app.js</code> und <code>greet.js</code>
SCSS ist im Prinzip eine vollwertige Programmiersprache, um CSS-Dateien modular zu erstellen.
die englischsprachige JSON-Datei landen, <code>grunt</code> laufen lassen und <code>index.html</code> öffnen.
Dann sollten Sie auf Englisch begrüßt werden. Das ist schon nicht schlecht, aber richtig DRY ist das noch nicht.
Sie müssen den Namen der JSON-Datei in '''zwei''' Dateien ändern. Also braucht es noch eine sechstes und letztes Hello-World-Tutorium ...


==Quellen==
==Quellen==
<references/>
<references/>
<ol>
<ol>
<li value="3"> {{Quelle|Kowarschick, W.: Multimedia-Programmierung}}</li>
<li value="5"> {{Quelle|Kowarschick, W.: Multimedia-Programmierung}}</li>
</ol>
</ol>
<noinclude>[[Kategorie: HTML5-Tutorium: JavaScript: Hello World]][[Kategorie: HTML5-Beispiel]][[Kategorie:Kapitel:Multimedia-Programmierung:Beispiele]]</noinclude>
<noinclude>[[Kategorie: HTML5-Tutorium: JavaScript: Hello World]][[Kategorie: HTML5-Beispiel]][[Kategorie:Kapitel:Multimedia-Programmierung:Beispiele]]</noinclude>

Version vom 12. April 2022, 09:56 Uhr

Dieser Artikel erfüllt die GlossarWiki-Qualitätsanforderungen nur teilweise:

Korrektheit: 3
(zu größeren Teilen überprüft)
Umfang: 4
(unwichtige Fakten fehlen)
Quellenangaben: 3
(wichtige Quellen vorhanden)
Quellenarten: 5
(ausgezeichnet)
Konformität: 3
(gut)

Vorlesung WebProg

Inhalt | Teil 1 | Teil 2 | Teil 3 | Teil 4 | Teil 5 | Teil 6 | Vue 1 | Vue 2 | Vue 3 | Vue 4 | Vue 5 | Vue 6

Musterlösung: index6.html (Git-Repository)

Anwendungsfälle (Use Cases)

Gegenüber dem dritten Teil des Tutoriums ändern sich die die Anwendungsfälle nicht. Die Anwendung leistet also genau dasselbe wie zuvor.

In diesem Teil des Tutoriums geht es darum, CSS durch SCSS zu ersetzen, um den CSS-Code „DRY zu machen“.

Erstellen eines neuen Projektes

Erstellen Sie ein neues Projekt HelloWorld06 als Fork von HelloWorld05 (siehe Hello-World-02-Tutorium).

git clone https://gitlab.multimedia.hs-augsburg.de/ACCOUNT/HelloWorld05 HelloWorld06
//git clone https://gitlab.multimedia.hs-augsburg.de/kowa/WK_HelloWorld05d HelloWorld06

## Änderungen zur Projektidentifikation vornehmen (z.B. Titel anpassen)
git commit -m "HelloWorld05 fork created"

# Neues Repository in Gitlab anlegen:
git remote -v
git remote remove origin
git remote add origin https://gitlab.multimedia.hs-augsburg.de/ACCOUNT/HelloWorld06
git remote -v
git push --set-upstream origin master

SCSS

Anstelle von CSS-Dateien verwenden Sie künftig SCSS-Dateien. Das ist zunächst einmal nicht weiter schwer, das jede CSS-Datei automatisch auch eine SCSS-Datei ist. Bei der Verwendung von CSS können Sie allerdings das Prinzip „Don't repeat yourself“ (DRY) nicht beachten. Sie müssen für verschiedene Elemente ständig Informationen wiederholen (gewünschter Font, Hintergrundfarbe, Größenangaben etc.). Deshalb gibt es mehrere Projekte wie z. B. LESS, Sass/SCSS, Stylus, die den CSS-Standard erweitern, um dieses Problem zu vermeiden. Sass verwendet allerdings eine ganz andere Syntax als CSS. Allerdings unterstützt das Sass-Projekt auch die Sprache SCSS, die CSS einfach um weitere syntaktische Elemente ergänzt. Zum Beispiel kann man in SCSS Konstanten definieren:

$background-color: #C5EFFC;

Und nun kann man in eine SCSS-Datei anstelle von #C5EFFC stets $background-color schreiben, um die Hintergrundfarbe von bestimmten Elementen zu definieren. Wenn man nun diese Farbe ändern will, muss das nicht mehr bei allen Elementen einzeln passieren. Es reicht, die Farbe in der Konstantendefinition abzuändern. Der SCSS-Code ist nun DRY.

Leider unterstützt kein Browser SCSS direkt. Aber für was gibt es Transpiler wie Webpack, die eine SCSS-Datei automatisch in eine CSS-Datei übersetzen können. Im fünften Teil des Hello-World-Tutorium haben wir im der Version 5d den SASS-Loader verwendet, um CSS-Dateien zu komprimieren. Damit haben wir aber gleichzeitig auch die Möglichkeit erhalten mit SCSS-Dateien an Stelle von CSS-Dateien zu verwenden.

Benennen Sie die Dateien src/css/head.css und src/css/body.css in src/css/head.scss und src/css/body.scss um. Ersetzen Sie außerdem in der Datei src/js/main.js den Import-Befehl

import '/css/body.css';

durch

import '/css/body.scss';

Zu guter Letzt müssen sie in webpack.config.js im Entry-Objekt folgende Ersetzung vornehmen:

head: absolutePath('src/css/head.css')

wird zu

head: absolutePath('src/css/head.scss')

Wenn Sie nun mittels npm run dev oder npm run prod Ihren Code übersetzen, sollte noch alle laufen, da der SASS-Loader die neuen SCCS-Dateien ebenfalls in CSS-Dateien übersetzt.

Ersetzen Sie in Ihrem Projekt die Datei src/css/main.css durch drei SCSS-Dateien: _config.scss, initial.scss und app.scss.

SCSS-Konfiguration

In der Datei _config.scss werden alle von den anderen SCSS-Dateien benötigten Konstanten definiert. Das heißt, das DRY-Prinzip „Konstanten gehören nicht in den Code, sondern in Konfigurationsdateien“ wird ab sofort beachtet. Wenn man künftig am Layout einen Zeichensatz, eine Farbe, einen Hintergrund oder Ähnliches ändern will, reicht es, die entsprechenden Konstanten anzupassen und schon erzeugt Webpack automatisch aktualisiere CSS-Dateien.

Der Underscore _ am Beginn des Dateinamens deutet an, dass diese SCSS-Datei nur von anderen SCSS-Dateien aber nicht von HTML- oder JavaScript-Dateien importiert werden. Durch SCSS-Import-Befehle ist es möglich, auch SCSS-Dateien zu modularisieren.

src/css/_config.scss

@use 'sass:math';

$background-color:  #C5EFFC;

$font-family-sans:  Verdana, Helvetica, sans-serif;
$font-family-serif: "Times New Roman", Times, serif;

$font-size-base:    3vw;
$font-size-factor:  1.25;  // cmp. https://type-scale.com/
 
$font-size-h5:      math.pow($font-size-factor,1)*$font-size-base;
$font-size-h4:      math.pow($font-size-factor,2)*$font-size-base;
$font-size-h3:      math.pow($font-size-factor,3)*$font-size-base;
$font-size-h2:      math.pow($font-size-factor,4)*$font-size-base;
$font-size-h1:      math.pow($font-size-factor,5)*$font-size-base;

$font-size-p:       math.pow($font-size-factor,0)*$font-size-base;
$font-size-p-large: math.pow($font-size-factor,2)*$font-size-base;

$font-size-small:   math.pow($font-size-factor,-1)*$font-size-base;

Konstanten starten in SCSS mit einem Dollarzeichen. Sobald eine Konstante definiert wurde, kann sie in allen weiteren SCSS-Konstrukten verwendet werden. In SCSS stehen einen Operatoren zur Verfügung wie +, -, * und /, um Maße zu berechnen. Es gibt weitere Operatoren zum Vergleichen von Zahlen und Maßen sowie zur Berechnung von Strings und booleschen Werten: https://sass-lang.com/documentation/operators.[1]

Die Datei _config.scss kann nun mit Hilfe des SCSS-Befehls @import 'config'; (ohne Underscore und ohne Endung) in die anderen beiden SCSS-Dateien eingefügt werden. Webpack (genauer gesagt der SASS-Loader von Webpack) kennt diesen Befehl und führt im beim Erstellen der zugehörigen CSS-Dateien auch aus.

Der Import-Befehl hat erst dann einen Effekt, wenn in den anderen Dateien auf diese Konstanten zugegriffen wird. Aber er schadet auch nicht, wenn auf keine der dort definierten Konstanten zugegriffen wird. Der Import-Befehl selbst taucht ebenso wenig in den generierten CSS-Dateien auf, wie die Konstantendefinitionen. Der Transpiler ersetzt Konstanten in CSS-Definitionen durch ihren jeweiligen Wert.

Sie können nun beispielsweise in der Datei head.scss die Konstante $background-color verwenden. In der daraus erzeugten CSS-Datei steht weiterhin der Farbwert #C5EFFC;

src/css/head.scss

@import 'config';

body
{ background-color: $background-color; }

.hidden
{ display: none; }

Die Datei body.scss ist deutlich umfangreicher. Daher wird der zugehörige CSS-Code ja auch erst gemeinsam mit der Datei web/js/main.js geladen.

src/css/body.scss

@import 'config';

html
{ height:  100%;
  width:   100%;
  display: table;
}

body
{ display:          table-cell;
  text-align:       center;
  vertical-align:   middle;
  background-color: $background-color;
  font-size:        $font-size-base !important;
  font-family:      $font-family-sans;
}

h1
{ padding:   0;
  margin:    0;
  font-size: $font-size-h1;
}

p, label
{ font-family: $font-family-serif;
  font-size:   $font-size-p !important;
}

label, input, button
{ width:      10em;
  font-size:  100%;
  display:    inline-block;
  box-sizing: border-box;
  margin:     0.5ex;
}

label
{ text-align: right;
}

#section_form
{ text-align:   center;
  margin-left:  auto;
  margin-right: auto;

  h1
  { margin-bottom: 0.5ex; }
}

#section_hello
{ p
  { font-size: $font-size-p-large !important; }
}

In dieser SCSS-Datei werden folgende SCSS-Erweiterungen verwendet:

  • Mathematische Berechnungen: @use 'sass:math';
  • Import-Befehl: @import 'config';
  • Konstanten: $font-family-sans, $font-size-base etc.
  • Verschachtelte Anweisungen: z. B. h1 innerhalb von #section_form

Die verschachtelten Anweisungen strukturieren den CSS-Code deutlich besser. Es ist nicht mehr notwendig einen Selektor wie #section_form mehrfach zu verwenden.

Sehen Sie sich den Unterschied an. In der Datei src/css/body.css der Musterlösungen vom dritten Teil des Tutoriums hatte ich Folgendes geschrieben:

#section_form
{ text-align:   center;
  margin-left:  auto;
  margin-right: auto;
}

#section_form > h1
{ margin-bottom: 0.5ex; }

Die SCSS-Variante ist deutlich strukturierter und prägnanter.

#section_form
{ text-align:   center;
  margin-left:  auto;
  margin-right: auto;

  h1
  { margin-bottom: 0.5ex; }
}

Insbesondere bei großen CSS-Dateien erweist sich diese kompaktere Schreibweise als vorteilhaft.

Weitere SCSS-Konstrukte

SCSS ist sehr nächtig. Es gibt neben der Import-Anweisung eine Use-Anweisung (@use)[2], die, SCSS-Konstrukten im Gegensatz zur Import-Anweisung einen Namespace zuweist. Damit ist es möglich mehrere SCSS-Module zu verwenden, auch wenn dieses gleichbenannte Elemente enthalten, ohne dass es zu Namenskollisionen kommt.

Darüber hinaus gibt es Mixins[3] und Funktionen[4]. Mit Mixins kann man ganze Styleblöcke definieren, um sie mehrfach zu verwenden. Mixins werden mit @include eingebunden. Dabei kann man Argumente an die Mixins übergeben, mit denen die entsprechenden Konstanten innerhalb des Mixins initialisiert werden. Funktionen funktionieren wie Funktionen in anderen Programmiersprachen auch. Es stehen einem If-Anweisungen und Schleifen-Befehle zur Verfügung.

SCSS ist im Prinzip eine vollwertige Programmiersprache, um CSS-Dateien modular zu erstellen.

Quellen

  1. Kowarschick (MMProg): Wolfgang Kowarschick; Vorlesung „Multimedia-Programmierung“; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2018; Quellengüte: 3 (Vorlesung)