1. Introduction

From Michael Nielsen (emphasis mine):

Technologies come and technologies go, but insight is forever.

and

Struggling with a project you care about will teach you far more than working through any number of set problems. Emotional commitment is a key to achieving mastery.

Before we learn to develop web applications, we need a basic understanding of the Internet and the World Wide Web. For a more in-depth explanation of these two terms, take a look at en.wikipedia.org/wiki/Internet and en.wikipedia.org/wiki/Hypertext_Transfer_Protocol. The Internet is a globally distributed network of networks. It connects billions of computers and devices allowing them to communicate with each other. The World Wide Web (WWW) is just one of many services running on the Internet. It is a huge collection of documents and other resources interlinked via hyperlinks. Each resource has a uniform resource locator (URL), which gives access to this resource. Typically we use browsers (e.g. Mozilla Firefox, Google Chrome, Microsoft Edge, Apple Safari) to access the Internet. Browsers use the Hypertext Transfer Protocol (HTTP) to communicate with other computers, so called web servers, on the Internet. The Internet uses a whole suite of protocols that are split into several layers. At the top level, the application layer, we have HTTP and many other protocols. Below, on the transport layer, we have the Transport Control Protocol (TCP). Beneath this layer we have the Internet Protocol (IP) on the Internet layer.

The WWW has evolved significantly since the early nineties. Today the web browser and related technologies are increasingly becoming the platform of choice for application development, for a number of reasons:

  1. Write once run anywhere. A web browser is installed by default on virtually every desktop, tablet, smartphone and other devices. A web application will run on all of these devices without requiring the user to download and install anything or the developer to provide executables for different operating systems.

  2. Updates are instantaneous, i.e. the next time the user uses the application, he/she will automatically be using the latest version.

  3. The performance of browser JavaScript engines rivals the best Java just in time compilers (JIT) and the gap to compiled C++ and assembler is dwindling. Today’s web apps use multithreading, accelerated 3D graphics and many other techniques that make full use of the available hardware.

  4. There are a large amount of standard application programming interfaces (API) as well as highly sophisticated open source libraries for all kinds of purposes.

  5. A virtually unlimited amount of documentation is available.

The following is a small sample list of web applications to provide a glimpse of what can be done:

2. Operating systems

Some recommendations on how to choose between Linux and Windows as a server platform can be found at www.singlehop.com/blog/linux-servers-vs-microsoft-windows-servers and www.1and1.com/digitalguide/server/know-how/linux-vs-windows-the-big-server-check among many others.

2.1. Ubuntu

2.1.1. Installation and configuration

The server guide provides the details. Get the ISO from Ubuntu and create a bootable USB stick using for instance Rufus.

If you want to upgrade an existing installation, see www.cyberciti.biz/faq/upgrade-ubuntu-18-04-to-20-04-lts-using-command-line.

If you have your own domain, use Certbot to get a free certificate. Use certbot --apache to create, certbot --apache --expand to expand and certbot renew to renew all certificates. Alternatively, for test purposes, you can create a self-signed certificate as shown in www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-apache-in-ubuntu-18-04.

SSLProtocol All -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
a2enmod headers

Add the following line to default-ssl.conf in the <VirtualHost default:443> directive:

Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"

Make sure that the file headers.load is in the mods-enabled folder. If it isn’t, copy it from mods-available. Add your site to hstspreload.org if you intend to use HTTPS over the long term.

Test your server security.

To set umask permanently, add umask 0027 to /etc/profile or change the following in /etc/pam.d/common-session (cf. serverfault.com/questions/231717/how-to-get-full-control-of-umask-pam-permissions):

session optional pam_umask.so umask=0027

If you get the error apache2: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1 when restarting Apache, edit your /etc/hosts file and make sure it contains 127.0.0.1 localhost servername.domain.com servername (cf. source).

.htaccess

In order to be able to use .htaccess files:

  1. The Apache rewrite module needs to be enabled, if it isn’t already:

    a2enmod rewrite
    apache2ctl restart
  2. The AllowOverride All directive needs to be in your Apache config file (usually in /etc/apache2) for the directory tree where your access file is located.

For the rest see Security.

Missing .Xauthority file

If you log in via SSH and get this message use

ssh -X user@host

to have the file created (source).

2.1.2. Administration

To simplify package management you might want to install wajig.

Command line

To learn the Linux command line study linuxcommand.org.

Useful commands
Recursively search for strings in files
grep -rHn "string" /path
Kernel version
uname -r
Last logged in users
last
Determine Ubuntu version
lsb_release -a

or

cat /etc/issue
Locate a file
whereis <filename>
List all files that were created today
find . -daystart -ctime 0 -print
find without permission denied messages
find / -name <name> -print 2>&-

which is equivalent to (cf. source):

find / -name <name> -print 2>/dev/null
chmod all directories but not files
find . -type d -exec chmod o+rx {} +
chmod all executable files

find . -executable -type f -exec chmod o+rx {} +

Activate root

sudo passwd root and give root a password. Afterwards, you can for instance run su -.

Setting umask permanently
Reconfigure package

dpkg-reconfigure package

Uninstall package completely

apt purge package

Nano jump to beginning or end of file

To jump to the beginning use Ctrl+W followed by Ctrl+Y. To jump to the end use Ctrl+W followed by Ctrl+V.

Monitor socket connections

ss

Exclude files/folders from archives
# https://stackoverflow.com/questions/984204/shell-command-to-tar-directory-excluding-certain-files-folders
# Note the files/folders excluded are relative to the root of your tar.
tar cfz /media/Backup232/www`date +%a`.tar.gz --exclude='owncloud' --exclude='everling.lu/WAD' /var/www 2>/dev/null
Redirect output streams
  1. Redirect stdout to one file and stderr to another file: command > out 2>error

  2. Redirect stderr to stdout (&1), and then redirect stdout to a file: command >out 2>&1

  3. Redirect both to a file: command &> out

Use wget to recursively download all files of a type
User login history

lastlog showing data from /var/log/lastlog.

To see detailed info view /var/log/auth.log.

Display your public IP address
Security
SSL/TLS

Proceed as follows to create a self signed certificate to be able to use HTTPS (cf. websiteforstudents.com/create-ssl-tls-self-signed-certificates-on-ubuntu-16-04-18-04-18-10):

openssl genrsa -aes256 -out server.key 4096
openssl rsa -in server.key -out server.key
openssl req -new -days 2000 -key server.key -out server.csr
openssl x509 -req -sha512 -days 2000 -in server.csr -signkey server.key -out server.crt
Antivirus
Main directories
Using USB drives

Find out what the drive is called using fdisk -l, then mount the drive using mount <drive> /media/usb. To unmount use umount /media/usb.

To have a drive mounted automatically, add it to /etc/fstab. Use lsblk -O or fdisk -l to get the required information for your drive. After a system reboot, your drive should be available.

Backup

System backup is essential. Install storeBackup, create a directory for your backups and add a crontab task using crontab -e. Here is an example crontab entry where an email is sent after backup completion (cf. how-to-sendmail):

* 3 * * 1 /opt/storeBackup/bin/storeBackup.pl --sourceDir /var/www --backupDir /root/backup
| sed 's/^/To: mail address\nSubject: backup\n\n/' | sendmail -t

Alternatively you can set up a systemd timer. A discussion about pros and cons can be found at cron vs systemd timers.

Instead of or in addition to local backup you might consider cloud backup using Duplicity, preferably with encryption.

Recover deleted files

Install and use extundelete.

Mail

Whilst you may not want to run your own mail server, if you want to enable your server to send emails, install Postfix or better a complete mail server. For Postfix configuration read steam.io/2013/04/01/postfix-rate-limiting and easyengine.io/tutorials/mail/postfix-debugging. To send an email, create a file with content structured as in the following example and then use sendmail recipient < file:

Subject: everling.lu backup job

Backup has been run

With regards to debugging Postfix, also see www.cyberciti.biz/faq/linux-unix-start-stop-restart-postfix

You can manage emails using mail or more comfortably using mutt.

sharadchhetri.com/2014/02/06/how-to-delete-mail-queue-in-postfix

Remote copy

See man rcp. The p, r and v options can be particularly useful.

rcp -prv source target

source can include the user name, e.g.

rcp -prv evegi144@students.btsi.lu:WAD .

would connect as user evegi144, ask for the password and then copy the WAD directory to the local folder.

Fail2ban

Alternative to stopping fail2ban:

From the Linux command prompt type: service fail2ban stop

To start fail2ban: service fail2ban start

To reload fail2ban if you have a banned IP: service fail2ban restart Restarting will clear the ban.

To prevent fail2ban from banning IPs on the local network or other places: Modify /etc/fail2ban/jail.conf look for the line:

#ignoreip 127.0.0.1 192.168.1.24/24 …​.

uncomment it by removing the # and then change the IP addresses. To have fail2ban ignore network 192.168.20.0 (255.255.255.0), add 192.168.20.0/24 to the above line. You can add as many networks as you like. Just leave a space.

Just a note, if you have a VPN or a tunnel, you should add its network too. I’ve had the tunnel banned!

You can see if fail2ban has banned an IP by checking /var/log/fail2ban.log. It will indicate banned and unbanned IP addresses.

To unban an IP address, use fail2ban-client set YOURJAILNAMEHERE unbanip IPADDRESSHERE

The hard part is finding the right jail: Use iptables -L -n to find the rule name then use fail2ban-client status to get the actual jail names. The rule name and jail name may not be the same but it should be clear which one is related to which (source).

Stop Apache DOS attacks as described in r3dux.org/2013/06/how-to-stop-apache-dos-attacks-with-fail2ban.

Grub2

Grub2 is the default boot loader and manager for Ubuntu.

cURL
git clone https://github.com/curl/curl.git
apt install autoconf libtool
./buildconf
./configure
Check disk health
apt install smartmontools
fdisk -l
smartctl -c /dev/sdX
smartctl -t short /dev/sdX
smartctl -H /dev/sdX
Install Gnome Tweaks and dconf-editor

These two tools are very useful to customize your Ubuntu desktop.

Check 3d performance

apt install nux-tools /usr/lib/nux/unity_support_test -p

2.2. Windows

2.2.1. Server

Introduction
Windows Server is the platform for building an infrastructure of connected applications, networks, and web services, from the workgroup to the data center.

Windows Server is used to serve all kinds of applications, data and services a client might require. Microsoft calls these roles and features. Roles are major capabilities required. For instance Active Directory to authenticate users or the Domain Name System (DNS) to locate other computers. Features can add additional functionality to the OS or enhance specific roles. Here you can find a list of the roles and features provided by Windows Server. There you can also see the differences between Windows Server Standard and Windows Server Datacenter. One of the major differences is that with the standard version you can only host 2 virtual machines per license.

The two Windows Server versions are available with different footprints either with desktop (Desktop Experience) or without. The advantage of the former being ease of use and of the latter performance and storage requirements.

This article provides much more in-depth information on the different Windows Server versions and is a must read.

Even without desktop experience it is still possible to run a number of GUI applications as illustrated in medium.com/@RealNetwork/windows-server-core-2019-gui-management-sysinternals-utilities-datacenter-standard-hyper-v-dashboard-265801412c89.

www.youtube.com/playlist?list=PLcRhfKiWZmM8L6r2vysrNaIz8inmdNQJk

www.microsoft.com/en-us/cloud-platform/windows-server

docs.microsoft.com/en-us/windows-server

www.microsoft.com/en-us/learning/companion-moc.aspx

www.classcentral.com/course/coursera-windows-server-management-and-security-9320

social.technet.microsoft.com/wiki/contents/articles/11608.e-book-gallery-for-microsoft-technologies-en.aspx

blogs.msdn.microsoft.com/microsoft_press/2016/09/26/free-ebook-introducing-windows-server-2016

www.discudemy.com/category/Windows%20Server

www.youtube.com/channel/UCP2uPp7TUXwJCicB0byzDnQ

winintro.ru

www.server-world.info/en/note?os=Windows_Server_2019

Planning

Starting with Windows Server 2016, we cannot convert between Core and Desktop anymore. Quote from docs.microsoft.com/en-us/windows-server/get-started/getting-started-with-server-with-desktop-experience:

Unlike some previous releases of Windows Server, you cannot convert between Server Core and Server with Desktop Experience after installation. If you install Server with Desktop Experience and later decide to use Server Core, you should do a fresh installation.
Migration

If you are planning to migrate Windows Server be sure to study docs.microsoft.com/en-us/windows-server/get-started/migrate-roles-and-features.

Installation

To be able to have several virtual machines communicate set the network mode in VirtualBox to NAT Network as described in www.techrepublic.com/article/how-to-create-multiple-nat-networks-in-virtualbox. Also see www.virtualbox.org/manual/ch06.html and www.nakivo.com/blog/virtualbox-network-setting-guide.

If you discover that your guest OS takes up a full core all the time, try assigning 2 cores to the guest VM via System → Processor in the VirtualBox Manager (cf. forums.virtualbox.org/viewtopic.php?f=6&t=87991&start=45).
winserver2016inst1
winserver2016inst2
winserver2016inst3

In previous Windows Server versions updates took ages so it was sometimes useful to disable them. This is not the case for Windows Server 2019 anymore, as the update speed has increased significantly. If you still want to disable updates, for the GUI version launch Services from the search box:

winserver2016conf1

Then run gpedit.msc → Computer Configuration → Administrative Templates → Windows Components → Windows Update and disable Configure Automatic Updates.

winserver2016conf2

For the version without GUI, run sconfig, select menu 5 and then set updates to manual.

Set the correct timezone:

winserver2016conf3

Now remove the disc from the virtual drive and select Devices → Insert Guest additions CD image…​ and run the guest additions. From the command line you’ll have to change to the CD drive and then run VBoxWindowsAdditions.exe.

Install BgInfo.

To see detailed info about the server run Get-CimInstance Win32_OperatingSystem|fl *.

To enable ping netsh advfirewall firewall add rule name="ICMP Allow incoming V4 echo request" protocol=icmpv4:8,any dir=in action=allow.

To enable RPC communication between server and client start your Windows client computer, run gpedit.msc and enable Computer Configuration → Administrative Templates → Network → Network Connections → Windows Firewall → Domain Profile → Windows Firewall: Allow inbound remote administration exception.

Install a real browser on both servers and disable Internet Explorer using dism /online /Disable-Feature /FeatureName:Internet-Explorer-Optional-amd64 in an elevated command prompt or PowerShell (see support.microsoft.com/en-us/help/4013567/how-to-disable-internet-explorer-on-windows).

Verify that remote management is enabled. This can be done via sconfig or Configure-SMRemoting -get in PowerShell or via the Server Manager GUI.

To execute cmdlets on remote servers, you need to specify the credentials as described in stackoverflow.com/questions/34768795/pass-password-into-credential.

To disable the monitor timeout on a server without GUI run powercfg -change -monitor-timeout-ac 0 (cf. ss64.com/nt/powercfg.html).

To see a list of installed roles and features:

Get-WindowsFeature|Where Installed or Get-WindowsFeature|Where-Object InstallState -eq Installed

You can be more specific, for example select only roles and features that begin with "Print" on computer server1 like this:

Get-WindowsFeature -Name Print* -ComputerName server1 -Credential (Get-Credential CORP\Administrator)|Where Installed

Install roles and features using Install-WindowsFeature, for example:

Install-WindowsFeature -Name DHCP -ComputerName server1

To remove use Uninstall-WindowsFeature.

To get a list of all PowerShell commands use Get-Command.

To get help on a command use help.

To run background jobs use Start-Job:

Start-Job {Get-WindowsFeature}

Get-Job allows us to see the state of a job.

To run a background job and see its output use Receive-Job:

$job=Start-Job {Get-WindowsFeature}

Receive-Job -Job $job

A new job can be scheduled:

$trigger=New-JobTrigger -Once -At 8:05AM Register-ScheduledJob -Name ListFeatures {Get-WindowsFeature} -Trigger $trigger $job=Start-Job {Get-WindowsFeature}

We can create persistent sessions:

$script1={Start-Job {Install-WindowsFeature -Name Windows-Server-Backup}}

$script2={Start-Job {Uninstall-WindowsFeature -Name Windows-Server-Backup}}

$srv1=New-PSSession -ComputerName server1

Invoke-Command $srv1 $script1

Disconnect-PSSession -Name $srv1

Get-WindowsFeature -Name Windows-Server-Backup -ComputerName server1

Connect-PSSession -Name $srv1

Invoke-Command $srv1 $script2

Get-PSSession|Remove-PSSession

To see which user you are logged in with use set or whoami.

To extend the Windows Server evaluation period, use slmgr -dlv to see the current status and slmgr -rearm to rearm.

To disable IPv6 using PowerShell see giritharan.com/disable-ipv6.

Deployment

The easiest way to deploy desktops and servers is Microsoft Deployment Toolkit (MDT).

Go here to get started.

Make sure to install both the ADK and the Windows PE add-on for the ADK (cf. osddeployment.dk/2018/12/30/unable-to-open-the-specified-wim-file-error-in-mdt-after-upgrading-to-adk-1809).

To fix failure (5616): 15299: Verify BCDBootEx for Windows 10 ADK 2004 see www.youtube.com/watch?v=W4Xfen6Slrk.

en.wikipedia.org/wiki/Preboot_Execution_Environment

docs.microsoft.com/en-us/windows/deployment/deploy-windows-mdt/get-started-with-the-microsoft-deployment-toolkit

Networking

www.slideshare.net/FabioAlmeida8/98-366-mva-slides-lesson-1

en.wikipedia.org/wiki/Private_network

www.lifewire.com/what-is-a-private-ip-address-2625970

www.microsoft.com/en-us/download/details.aspx?id=8781

simpledns.com/private-ipv6

Private IP addresses

We can use the following IP address ranges as private or local IP addresses, which will not be visible on the internet:

  1. 10.0.0.0 to 10.255.255.255

  2. 172.16.0.0 to 172.31.255.255

  3. 192.168.0.0 to 192.168.255.255

Networking tools
  1. ping

  2. tracert

  3. pathping

  4. Test-Connection (PowerShell)

  5. telnet

  6. Test-NetConnection (PowerShell)

  7. Get-NetAdapter (PowerShell)

Active Directory Domain Services (AD DS)

According to this recommended introduction by Microsoft:

AD DS provides a centralized system for managing users, computers, and other resources on a network.

From "Installing and Configuring Windows Server 2012 Training Guide" by Mitch Tulloch:

Active Directory Domain Services (AD DS) provides a distributed database and directory service that stores and manages information about the users, computers, groups, shares, printers, and other types of objects that comprise an organization’s IT infrastructure.

Windows Server 2019 does not provide any new AD functionality or even forest level (cf. www.virtualizationhowto.com/2018/12/upgrading-windows-server-2016-domain-controller-dc-to-windows-server-2019).

First we need to install the AD DS role via Server Manager or PowerShell. Then the server needs to be promoted to a domain controller. See blogs.technet.microsoft.com/canitpro/2017/02/22/step-by-step-setting-up-active-directory-in-windows-server-2016 and www.moderndeployment.com/windows-server-2019-active-directory-installation-beginners-guide.

In PS we can use Install-ADDSForest to create a new forest, domain and domain controller.

To do it remotely via PowerShell:

Install-WindowsFeature -name AD-Domain-Services -ComputerName winsecore -Credential (Get-Credential CORP\Administrator)

Invoke-Command –ComputerName winsecore -credential (get-credential CORP\Administrator) {Import-Module ADDSDeployment;Install-ADDSDomainController –NoGlobalCatalog:$False –CreateDNSDelegation:$False –Credential (Get-Credential CORP\Administrator) –CriticalReplicationOnly:$False –DatabasePath “C:\Windows\NTDS” –DomainName “corp.contoso.com” –InstallDNS:$True –LogPath “C:\Windows\NTDS” –NoRebootOnCompletion:$False –SiteName “Default-First-Site-Name” –SysVolPath “C:\Windows\SysVol” }

Don’t forget to set the DNS server.

Problems with AD almost always result from a DNS misconfiguration.
In order to successfully promote a second server as domain controller several reboots of the server and the existing domain controller are usually required.

If you encounter an error mentioning a duplicate SID, for instance because you cloned a VM, you need to generate a new SID (cf. www.mustbegeek.com/generate-new-sid-server-2012), which will reset a lot of settings.

Useful commands include Get-Command -AD, Get-ADDomain|fl name,DomainMode, Get-ADForest|fl name, DomainMode.

You can navigate the AD using PowerShell like so:

CD AD:

DIR

CD "DC=corp,DC=contoso,DC=com"

DIR

CD CN=Users

DIR | FT -a

Get-ADUser -Filter {name -like "*"}

When you add a new non-admin user and try to log them in, you’re likely to get the following error message: "The sign-in method you are trying to use isn’t allowed. For more info, contact your network administrator". This is due to the default domain controllers policy (cf. link). To solve this problem, open the Default Domain Controllers Policy and check who is allowed to log on locally:

winserver2019LocalLogOnGPO1

In this case you can see, that the user is only member of the group Domain Users which is not allowed to log on locally. So either you add the user to a group that is allowed to log on locally or you add at least one of the user’s groups to the allowed ones. Then you run gpupdate /force and the user should be able to log in.

If you cannot contact a domain controller, see theitbros.com/active-directory-domain-controller-could-not-be-contacted.

cp-mlxprod-static.microsoft.com/05329-1025/en-us/content/content_8xaxrrjy_1704984382/04232015094701.pptx

channel9.msdn.com/Series/Using-PowerShell-for-Active-Directory

channel9.msdn.com/Series/Active-Directory-Video-Series/ADs-Reliance-on-DNS

www.varonis.com/blog/top-10-active-directory-tutorials-web

www.slideshare.net/nishadsukumaran/active-directory-training

www.youtube.com/watch?v=nKcrVtvZvpk

www.youtube.com/watch?v=J8uw3GNZxzQ

Replication

To list commands relevant to replication: Get-Command Replication To list replication partners: Get-ADReplicationPartnerMetaData -target corp.contoso.com

Group policy
The official group policy settings reference can be found at tinyurl.com/policysettings-xls.

docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/dn789193(v%3Dws.11)

4sysops.com/archives/four-ways-to-search-for-group-policy-settings

www.linkedin.com/learning/windows-server-2012-r2-manage-group-policy/configure-group-policy-preferences

docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc786524(v%3dws.10)

docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/ee461027(v=technet.10)

docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc733087(v%3dws.10)

social.technet.microsoft.com/wiki/contents/articles/51876.group-policy-filtering-and-permission.aspx

www.infoworld.com/article/3117286/tutorial-the-joys-of-windows-servers-group-policies.html

www.grouppolicy.biz/tutorials

www.mdmandgpanswers.com/blogs

sdmsoftware.com/gpoguy

sdmsoftware.com/gpoguy/free-tools/video-training

www.heidelbergit.dk

To redirect the default location of new users and computers, see support.microsoft.com/kb/324949.

The Local Users and Groups snap-in is not accessible on a domain controller. Use the Group Policy Management Editor to manage local users and groups as shown below.
Use gpresult /user <username> /z to get a detailed command line view of the applied group policies.

www.grouppolicy.biz/2010/05/how-to-apply-a-group-policy-object-to-individual-users-or-computer

woshub.com/group-policy-not-applied-troubleshooting

docs.microsoft.com/en-us/previous-versions/windows/desktop/policy/filtering-the-scope-of-a-gpo

superuser.com/questions/1082522/gpo-denied-security-filter-not-applying

Group policy applies only to users or computers in an OU, not a group.

See www.grouppolicy.biz/2010/05/how-to-apply-a-group-policy-object-to-individual-users-or-computer on how to apply a group policy object to individual users or computers.

If you’re getting "GPO Denied (Security Filter) not applying" see superuser.com/questions/1082522/gpo-denied-security-filter-not-applying. You need to make sure, that Authenticated Users have read access to the GPO.

interactivelogon

Local users and groups

The easiest way to configure local users and groups is va the Group Policy Management Editor:

GPMELocalUsersAndGroups
Restricted Groups policy
Restricted Groups is a client configuration means and cannot be used with Domain Groups. Restricted Groups is designed specifically to work with Local Groups.
The only situation where it makes sense to use Restricted Groups policy is when you want to ensure that certain users are members of an Active Directory group. Otherwise use the Local Users and Groups parts of the GPME.
GPMERestrictedGroups
There’s no merging between Restricted Groups policy settings set up at multiple levels in Active Directory. The last applied policy wins.
Read this excellent article.
Group Policy Management Console Scripting Samples
Windows Admin Center

www.microsoft.com/en-us/cloud-platform/windows-admin-center

Cannot be installed on domain controller machines. But if you install it before installing the DC it will still work afterwards!
BitLocker
EFS
Tips & Tricks
See computer name

hostname

Rename computer using PS

Rename-Computer -NewName <xyz> -Restart

Get current IP configuration

Get-NetIPAddress

Assign a new IP address

New-NetIPAddress -InterfaceIndex <x> -IPAddress <y> -PrefixLength <z> -DefaultGateway <abc>

Renew IP configuration

ipconfig /renew

Restart computer

shutdown /r /t 0

2.2.2. Client

A fantastic tutorial collection can be found at www.tenforums.com/tutorials/1977-windows-10-tutorial-index.html.

To get the ISO file and create a bootable USB you can use Rufus.

Administration
DNS

Display data in the DNS resolver cache:

ipconfig /displaydns

Flush DNS resolver cache:

ipconfig /flushdns

Renew all DHCP leases and reregister all DNS names:

ipconfig /registerdns

Trace a route to a server:

tracert hostname
pathping hotname
Robocopy

Useful options include /S /PURGE /COPYALL /DCOPY:T /R:2 /W:1 /A-:SH /xj.

To get rid of undeletable recursive directories (cf. answers.microsoft.com/en-us/windows/forum/windows_7-files/windows-7-infinite-loop-while-using-robocopy/20f32f0c-4cb9-4125-923d-6a57e4d27232) we create an empty dir and then robocopy empty dest /MIR.

Tips & Tricks

Get rid of language bar icon

www.askvg .com/fix-input-indicator-icon-comes-back-in-taskbar-notification-area-after-restarting-windows[^]

www.howtogeek.com/howto/windows/bring-misplaced-off-screen-windows-back-to-your-desktop-keyboard-trick

Fix DPC WATCHDOG VIOLATION

www.youtube.com/watch?v=VXgAFmPI21g

How to Add Programs, Files, and Folders to System Startup in Windows

www.howtogeek.com/208224/how-to-add-programs-files-and-folders-to-system-startup-in-windows-8.1

List of Windows tools

www.ghacks.net/2017/06/11/list-of-windows-tools

windowsreport.com/weather-app-live-tile-not-working-windows-10

How to access the BIOS

www.addictivetips.com/windows-tips/access-bios-pc

Get rid of hiberfil.sys

www.howtogeek.com/howto/15140/what-is-hiberfil.sys-and-how-do-i-delete-it

How to convert Windows installations to virtual machine images

lt3000.blogspot.com/2018/09/on-chinas-putative-real-estate.html

15 Windows 10 Run Commands Everyone Should Learn

helpdeskgeek.com/windows-10/windows-10-run-commands-everyone-should-learn

How to launch apps automatically during startup on Windows 10

www.windowscentral.com/how-launch-apps-automatically-during-startup-windows-10

stackoverflow.com/questions/8976287/recursive-unzipping-with-7z-exe

How To Pin Shortcut To Taskbar When There’s No “Pin To Taskbar” Option

media-moon.com/blog/windows-10-how-to-pin-shortcut-to-taskbar-when-theres-no-pin-to-taskbar-option

Disk drive defragmentation

www.tenforums.com/performance-maintenance/118761-optimize-drives-says-i-have-ssd-when-i-have-hdd.html

PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity

github.com/microsoft/PowerToys

www.wikihow.com/Delete-a-User-Account-Picture-in-Windows-10

How to run Linux desktop on Windows

www.makeuseof.com/tag/linux-desktop-windows-subsystem

Windows 10 keyboard shortcuts

helpdeskgeek.com/windows-10/windows-10-keyboard-shortcuts-the-ultimate-guide

Windows 10 wakes up from sleep

windowsreport.com/windows-8-windows-10-wakes-sleep-fix

How to remove admin rights

thycotic.com/company/blog/2019/04/09/how-to-remove-admin-rights

2.3. MacOS

2.3.1. Find network printer IP address

Browse to localhost:631/printers. To enable the cups page, run cupsctl WebInterface=yes in a terminal (see apple.stackexchange.com/questions/198037/how-do-i-get-the-actual-ip-address-of-a-printer-in-osx-yosemite).

To access network printer via virtual box use bridged mode network adapter (cf. forums.virtualbox.org/viewtopic.php?f=2&t=86993).

2.3.2. Take a screenshot

3. Tools of the trade

3.1. Portable work environment

3.1.1. Vagrant

Vagrant serves to isolate dependencies and their configuration within a single disposable, consistent environment, without sacrificing any of the tools you are used to working with (editors, browsers, debuggers, etc.). Once you or someone else creates a single Vagrantfile, you just need to vagrant up and everything is installed and configured for you to work. Other members of your team create their development environments from the same configuration, so whether you are working on Linux, Mac OS X, or Windows, all your team members are running code in the same environment, against the same dependencies, all configured the same way. Say goodbye to "works on my machine" bugs.

3.1.2. Docker

Docker containers wrap a piece of software in a complete filesystem that contains everything needed to run: code, runtime, system tools, system libraries – anything that can be installed on a server. This guarantees that the software will always run the same, regardless of its environment.

If you run into docker: Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: run usermod -a -G docker <user> (cf. techoverflow.net/2017/03/01/solving-docker-permission-denied-while-trying-to-connect-to-the-docker-daemon-socket).

Kill all docker containers at once: gist.github.com/evanscottgray/8571828

3.1.3. VirtualBox

The techniques and features that VirtualBox provides are useful for several scenarios:

  • Running multiple operating systems simultaneously. VirtualBox allows you to run more than one operating system at a time. This way, you can run software written for one operating system on another (for example, Windows software on Linux or a Mac) without having to reboot to use it. Since you can configure what kinds of "virtual" hardware should be presented to each such operating system, you can install an old operating system such as DOS or OS/2 even if your real computer’s hardware is no longer supported by that operating system.

  • Easier software installations. Software vendors can use virtual machines to ship entire software configurations. For example, installing a complete mail server solution on a real machine can be a tedious task. With VirtualBox, such a complex setup (then often called an "appliance") can be packed into a virtual machine. Installing and running a mail server becomes as easy as importing such an appliance into VirtualBox.

  • Testing and disaster recovery. Once installed, a virtual machine and its virtual hard disks can be considered a "container" that can be arbitrarily frozen, woken up, copied, backed up, and transported between hosts.

  • On top of that, with the use of another VirtualBox feature called "snapshots", one can save a particular state of a virtual machine and revert back to that state, if necessary. This way, one can freely experiment with a computing environment. If something goes wrong (e.g. after installing misbehaving software or infecting the guest with a virus), one can easily switch back to a previous snapshot and avoid the need of frequent backups and restores.

  • Any number of snapshots can be created, allowing you to travel back and forward in virtual machine time. You can delete snapshots while a VM is running to reclaim disk space.

  • Infrastructure consolidation. Virtualization can significantly reduce hardware and electricity costs. Most of the time, computers today only use a fraction of their potential power and run with low average system loads. A lot of hardware resources as well as electricity is thereby wasted. So, instead of running many such physical computers that are only partially used, one can pack many virtual machines onto a few powerful hosts and balance the loads between them.

druss.co/2015/06/fix-vt-x-is-not-available-verr_vmx_no_vmx-in-virtualbox

www.nakivo.com/blog/virtualbox-network-setting-guide

www.oracle.com/technical-resources/articles/it-infrastructure/admin-manage-vbox-cli.html

3.2. Integrated Development Environments

3.2.2. Visual Studio Code

3.2.3. Codiad

Codiad is a web-based IDE framework with a small footprint and minimal requirements.

3.2.4. Atom

Get the editor from atom.io. Installation instructions can be found in the flight manual. It is recommended to install the two Asciidoc packages for Atom as mentioned in Asciidoc live preview. Activate live preview with ctrl-shift-a as described in asciidoc-preview.

Portable installation

Follow Portable Mode in flight-manual.atom.io/getting-started/sections/installing-atom. To create the .atom folder for the portable installation see gist.github.com/ozh/4131243.

3.2.5. PhpStorm

PhpStorm is the ideal IDE for web app development. It provides full database and server integration.

Portable installation

To install PhpStorm on a portable drive, go to JetBrains and click the Download button. Cancel the automatic download of the .exe file and right click direct link, select Copy Link Location, paste the link into a new tab and replace the exe extension with zip, then press enter. This will download and open the zipped version of PhpStorm. Extract it to your portable drive.

Open the file bin/idea.properties, replace the line starting with #idea.config.path with idea.config.path=${idea.home}/.WebIde/config, #idea.system.path with idea.system.path=${idea.home}/.WebIde/system, #idea.plugins.path with idea.plugins.path=${idea.config.path}/plugins and #idea.log.path with idea.log.path=${idea.system.path}/log.

In order to avoid having to reenter your SSH password after every logout set the following:

phpStormPortable1

This works only for project deployment servers, not for global ones. Unfortunately this does not work for DB sources for which you’ll have to reenter the SSH password.

If you have settings from another PhpStorm installation that you’d like to import, you can do this via File → Import Settings…​.

Project setup

First, we set all file encodings to UTF-8 in order to avoid any problems with special characters. Search for file encodings in the search box. Given the constant PhpStorm UI changes, your file encoding settings may be located in a different place:

File encodings

Now we configure a new project:

phpStorm1
phpStorm2
phpStorm3
phpStorm4
phpStorm5
phpStorm6
phpStorm7
phpStorm8
phpStorm9
phpStorm10
phpStorm11
phpStorm12
phpStorm13
Database connection setup

First we need to make sure that the drivers are loaded:

createDB2

Then we need to create a data source:

createDB3

Make sure to right click the connection and select Make Global so that you don’t need to configure it for each project:

createDB4
Template adjustment
PhpStorm template adjustment
Tips

Change the retention period for local history: www.jetbrains.com/help/phpstorm/local-history.html#location.

3.2.6. NetBeans

Download NetBeans.

NetBeansDownload1

If this is the first time you install NetBeans on your device, you need to install the Java Development Kit (JDK) first (point 1 on the screenshot). This will open the following screen:

JDKDownload1
JDKDownload2

Accept the license agreement and select the right JDK version for your operating system.

When the JDK is installed you can install NetBeans. For our purposes we only need the HTML5 + PHP version (point 2).

Alternatively you can install the NetBeans Java SE bundle (point 3), which includes the JDK and NetBeans. This will taker you to the following screen:

NetBeansJDKDownload1

Accept the license agreement and select the right JDK version for your operating system.

Portable installation

If you want to install NetBeans on a portable device, you can download it as a zip file (point 4 on the first screenshot in the previous subsection.) This will take you to the following screen:

NetBeansPortable1
HTML5 Project setup

Click on NetBeansNewProjectIcon or File → New Project or Ctrl+Shift+N:

NetBeansHTML5Project1

Specify the name of your project and where you’d like to save it:

Name and locate a new NetBeans HTML5 project

We don’t use site templates:

Site template selection

We also don’t use a JavaScript library, so we can just click on Finish:

JavaScript library selection

You can now see your new HTML5 project structure in the upper left corner. NetBeans has also opened the index.html file, which is the default name of the main project HTML5 file:

Our new HTML5 project

The content of this file is defined in the corresponding template. See NetBeans templates for guidance on how to change this.

In order to add a new file to your project, right click on Site Root and select the file type:

Adding a new file to the HTML5 project
PHP Project setup

Click on NetBeansNewProjectIcon or File → New Project…​ or Ctrl + Shift + N. If you are using an older version of NetBeans (< 7.4), you may need to install the PHP plugin via Tools → Plugins → Available Plugins and select PHP. After restarting NetBeans, you should get the following screen when creating a new project:

Create a new NetBeans PHP project

Specify the name of your project and where you’d like to save it. Choose the latest PHP version and keep UTF-8 as the default encoding. The latter makes sure, that non-English characters such as é or ä are handled correctly:

Name and locate a new NetBeans project

If you want to run your project on your local web server, select the corresponding option. We’ll run our projects on Foxi, thus we specify Remote Web Site (FTP, SFTP):

NetBeans run configuration

In order to be able to upload our files to Foxi, we need to define a remote connection, thus we need to click on Manage…​.

Create new connection

The host name is foxi.ltam.lu. The port number needs to be 22. Enter your IAM code as user name and your 11-digit matricule as password (cf. FOXI_login_2017.pdf) to learn how to change your password). The initial directory should be set to /www/your class/your IAM code:

Manage remote NetBeans connection

Now click the connection test button. You should get the following prompt, which you should confirm:

Foxi certificate confirmation

The following dialog should appear:

Foxi connection success

Now you can click on OK. We do not use any PHP framework, so you can click the Finish button in the final dialog. In the projects window (top left) you should now see your new PHP project. You can expand the project structure by clicking on the +-sign in front of it. Under Source Files you’ll see your new PHP project:

New PHP project

You can now start working on your project. When you save your changes, you’ll have to confirm that you want to connect to Foxi. You’ll then see confirmation in the output window that the file has been uploaded to Foxi:

NetBeans output window

We can verify this using our SFTP client (cf. SFTP):

Check NetBeans file upload with WinSCP

We can add a new file to our project by right clicking on Source Files and selecting New  PHP File…​:

NetBeans project setup
Database connection setup

In order to connect to MySQL on Foxi we need to open a secure shell (SSH) tunnel. Given that NetBeans does not provide a built-in tunnel functionality, we need to use an external SSH client, for instance Putty.

Enter the tunnel data:

Tunnel data

Then add the tunnel:

Tunnel

Save the session:

Tunnel session

Create a new DB connection:

New DB connection 1
New DB connection 2
New DB connection 3

Set the default DB:

Default DB 1
Default DB 2

View table data:

View table data 1
View table data 2
Template adjustment
Template 1
Template 2
Template 3
Useful NetBeans shortcuts

Pressing Alt+Shift+F or selecting Source  Format will reformat the source code according to the settings in Tools  Options:

Reformat the source code

3.3. SSH

3.3.1. Clients

You can connect to your server using a secure shell (SSH) client such as Putty, which is however rather rudimentary. Therefore you might prefer to use more convenient GUIs, most of which use Putty in the background:

3.3.2. SFTP

SFTP is the secure, i.e. encrypted, version of FTP, the file transfer protocol. As its name suggests, it is used to transfer files from our development machine to the server and vice versa. There are a number of SFTP clients freely available, e.g. Filezilla. I prefer WinSCP. Download the portable executable and unzip it to a folder of your choice. Set the configuration storage option on the storage page in the preferences dialog to INI file. This will lead WinSCP to save its configuration in an ini file in the same folder where the program itself is located. If you have stored WinSCP on your USB stick, the configuration will also be stored there, so you won’t have to reenter the server data every time you use the program:

Set WinSCP storage preferences

Set up your server connection and click save. Click login to connect to the server and begin transferring your files:

Configure WinSCP login

3.4. Browsers

3.4.1. Firefox

If you incur problems loading a web page that works with other browsers, the source is often to be found with a specific add-on. To confirm this is the case, close Firefox and start it in safe mode, for instance by holding the Shift key pressed whilst launching Firefox (cf. Safe Mode).

To see all preferences that can be set, enter about:config in the address bar.

3.5. Documentation

3.5.1. Jupyter notebooks

jupyter.org

github.com/n-riesco/ijavascript

3.5.2. Asciidoctor

Tips & tricks

3.6. Content Management Systems

According to Wikipedia:

A content management system (CMS) manages the creation and modification of digital content. These systems typically support multiple users in a collaborative environment, allowing to perform document management with different styles of governance and workflows. Usually the content is a website (or part of it) and the term commonly refers to web content management systems. Web content may include text and embedded graphics, photos, video, audio, maps, and program code (such as for applications) that displays content or interacts with the user. By their nature, CMSs support the separation of content and presentation.

Basically a CMS aims to enable the creation and maintenance of a web site without any knowledge of HTML, CSS, JavaScript etc. There are many CMS out there, but Wordpress seems to be the most popular by a wide margin. According to W3Techs as of September 20, 2020:

39.6% of the websites use none of the content management systems that we monitor. WordPress is used by 38.4% of all the websites, that is a content management system market share of 63.6%.

However, it is important to choose a CMS based on your specific requirements. As this article argues, there’s no "best" CMS, each CMS has its strengths and weaknesses and is best suited for specific types of projects and environments.

Using an open-source CMS such as WordPress may not always be the best solution, see for instance 7 Solid Reasons not to Use WordPress.

3.6.1. Wordpress

Wordpress provide detailed installation instructions. After installation you should study first steps and wordpress.org/support/article/roles-and-capabilities

4. Client side programming

For a very high level overview, see roadmap.sh/frontend.

4.1. HTML5

HTML stands for Hyper Text Markup Language. HTML5 is the latest version of this markup language for describing web documents or pages. It consists of a series of tags. An element or tag is like a command or instruction that tells the browser about the structure and meaning (also called semantics) of the content of a specific part of our web page.

Take a look at this very gentle, enjoyable and effective introduction to the subject of web design.

Here is a great listing and explanation of all tags with examples. The official standard can be found here and the complete set of HTML elements here. Cheat sheets can be very helpful.

4.1.1. Basic structure

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>HTML5 Skeleton</title>
    <meta charset=UTF-8>
    <link href=style1.css rel=stylesheet>
    <script src=script1.js></script>
  </head>
  <body>

  </body>
</html>
1
2
3
body {
  background-color: lightseagreen;
}
1
window.alert("Our first JavaScript has been loaded and executed!");

The first line of an HTML5 document should tell the browser how to process the document by specifying the Document Type Definition (DTD).

After the DTD comes the <html> tag, which specifies the language using the lang attribute. See tag list for a list of available language codes. The <html> tag encompasses the whole HTML document consisting of a <head> and a <body> part.

<head>

In the head part we specify the title and the character encoding, which for our purposes will be UTF-8. UTF-8 has the advantage that it handles special characters, e.g. ö and é, correctly. To learn more about character encodings, see www.w3.org/International/tutorials/tutorial-char-enc. Then we include our external CSS and JavaScript files (more on those in the following chapters).

The following elements can go inside the <head> element:

  • <title> (this element is required in the head section)

  • <style>

  • <base>

  • <link>

  • <meta>

  • <script>

  • <noscript>

<body>

The body part contains the actual page content.

Opening and closing tags

For most, but not all, of the HTML5 tags, there is an opening and a closing tag, as in <body></body>. There are a few standalone tags, such as <hr> to display a horizontal line.

Tabs, new lines and spaces

Browsers ignore tabs, new lines and most spaces. For instance, the following two HTML documents produce exactly the same output except for the words "a well", which have been replaced with "an ill":

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Example of a well formatted HTML document</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      This is a well formatted HTML document.
    </main>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html



              lang=en>




  <head><title>Example

    of       an ill          formatted
  HTML document</title>
    <meta charset=UTF-8></head><body><main>This is    an
  ill formatted HTML document.</main></body></html>
Comments

In order to help others (and ourselves) understand our HTML documents, it is a good idea to include comments where appropriate. Comments are embedded between <!-- and -->. A comment can span several lines and is not displayed by the browser.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html> <!-- The document type is compulsory. -->
<html lang=en> <!-- Don't forget to specify the language. -->
  <head>
    <!--
      This is a very simple illustration of comment usage in HTML5.
      You do not have to use comments.
      Use them where it makes sense.
    -->
    <title>This is an example of comment usage in HTML5</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <!-- The main part is currently empty. If you have a good idea
         on how to fill it, let me know! :D
      -->
    </main>
  </body>
</html>

4.1.2. Validation

In order to be sure that our HTML5 document complies with the official standard and should thus run according to our plans in all compliant browsers, we need to validate our HTML5 and CSS3 files either using the official validators at validator.w3.org and jigsaw.w3.org/css-validator or using the Firefox extension users.skynet.be/mgueury/mozilla/index.html. The latter will install a validation button in the Firefox add-on bar. A simple double click will display the source code of the current page and run it automatically through the official HTML5 validator. With a right click on the button we launch the CSS3 validator via the Advanced menu. Here are the outputs of the validators for the solution of the next exercise:

The W3C HTML validator
The HTML validation Firefox extension
Launching the W3C CSS validator
The W3C CSS validator

The warning messages can be safely ignored. They just tell us that the validator is still experimental. Given that the HTML5 standard is not expected to be finalized for many years, this is unlikely to change any time soon.

4.1.3. Planning

In order to produce a top notch web site, we need to plan our work carefully.

Brain storming

First we need to think about the purpose of our web site. What are the big concepts and ideas that will drive our content? A useful tool in this respect is a mind map. We’ll be using the open source FreeMind software, which is available from freemind.sourceforge.net/wiki/index.php/Main_Page.

As an example, here’s the mind map for WMOTU Lab v1:

mind map
Blueprint

Now that we have clarified the big picture content of our site, it’s time to sketch out the rough and basic structure. For this purpose we’ll use an open source vector drawing software named Inkscape.

WMOTU Lab v1 structure
Requirements specification

The standard professional approach to project planning is to produce a requirements specification. Such a document specifies the project requirements, including:

  1. Functionality

  2. Prototype/model

  3. Logical site structure

  4. Physical site structure

  5. Time plan

  6. Development environment and technologies

Here is a minimalist example for the WMOTU Address Book app developed in WMOTU Address Book:

Functionality

The app serves as an electronic address book. New users need to sign up by providing a login name and password. After logging in, the user enters the main page, where he can logout and view a listing of all his addresses. He can delete or edit each address as well as add a new one. All addresses are stored in a MySQL database on the server.

Physical site structure
WMOTU Address Book Physical
Time plan

The final product will be delivered electronically on 24.6.14.

Development environment and technologies

Development will be done mainly with PhpStorm. Main technologies used will be HTML5, CSS3, PHP5 and MySQL5.

4.1.4. <br>

As we have seen, new lines in our source code are converted to a single space by the browser. To split our text into different lines, we use the <br> tag, which inserts a line break. As already mentioned in this chapter, for most, but not all, HTML5 tags there is an opening and a closing tag. <br> is one of the exceptions. It is a so called empty tag, meaning it has no closing tag. This tag should not be used to separate paragraphs. For the latter purpose we use the <p> tag, cf. <p>.

Example:

br
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Break row example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      This is the first line.
      This should be the second one.<br>
      This is the second one.
    </main>
  </body>
</html>

4.1.5. <p>

This tag is used to mark up a paragraph. The browser automatically adds margin above and below each paragraph (see section Block vs inline elements).

Example:

p1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Paragraph example</title>
    <meta charset=UTF-8>
    <style>
      #p1 {
        background-color: green;
      }

      #p2 {
        background-color: gold;
      }
    </style>
  </head>
  <body>
    <main>
      <p id=p1>
        This is the first paragraph. Note that the text always occupies the full
        width of the browser window. If you change the width of your browser window,
        the number of lines that your paragraph occupies changes too.
      </p>
      <p id=p2>
        This is the second paragraph. Use the Firefox console to inspect the margins
        used by your browser.
      </p>
    </main>
  </body>
</html>

Resize your browser and observe the behavior of your paragraphs. Note that we’ve given each paragraph an id attribute. This allows us to style each paragraph’s background color individually using CSS. More on this in CSS3.

4.1.6. Phrase tags

Phrase tags are used to convey special meaning to text:

Name Description

<em>

emphasized text

<strong>

important text

<dfn>

definition term

<code>

computer code

<samp>

sample output from a computer program

<kbd>

keyboard input

<var>

variable

Here is a simple application:

Phrase tags
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Phrase tags example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <p>I'd like to emphasize <em>the following</em>. This is particularly
      <strong>important</strong>.</p>
      <p><dfn>HTML5</dfn> is the definition of greatness!</p>
      <p>The secret of the universe looks like this:
        <code>if (sunshine === true) window.alert("Smile!");</code>
      This will hopefully produce this output: <samp>Smile!</samp></p>
      <p>Enter <kbd>WMOTU</kbd> as your user name. It will be stored in
        <var>userName</var></p>
    </main>
  </body>
</html>

4.1.7. HTML entities

Some characters, such as < or >, are reserved in HTML. We thus cannot use them directly in our text as the browser would try to interpret them as part of a tag.

To get around this problem, we use character entities. A character entity has the form &entity_name or &#entity_number. The following table lists the reserved characters and their corresponding entities (see dev.w3.org/html5/html-author/charref for the complete list and digitalmediaminute.com/reference/entity for the Unicode codes):

Character Entity number Entity name Description

"

&#34;

&quot;

quotation mark

'

&#39;

&apos;

apostrophe

&

&#38;

&amp;

ampersand

<

&#60;

&lt;

less than

>

&#62;

&gt;

greater than

Application example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Entities usage example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      The HTML expert said &#34;Use HTML entities to display special characters in
      HTML&quot;. As you know, HTML tags start with an &lt; and close with a &gt;, as in
      <code>&lt;a&gt;</code>.
    </main>
  </body>
</html>

4.1.8. <header>

The <header> tag specifies a header for a document or section. It should be used for introductory content or navigation elements. You can have several of these in one document, but they cannot be placed within a <footer>, <address> or another <header> element.

<h1> …​ <h6>

These tags specify headings at different levels:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Heading Example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <header>
      <h1>Heading level 1</h1>
      <h2>Heading level 2</h2>
      <h3>Heading level 3</h3>
      <h4>Heading level 4</h4>
      <h5>Heading level 5</h5>
      <h6>Heading level 6</h6>
    </header>
  </body>
</html>

A heading

4.1.9. Lists

We can choose between unordered and ordered lists. In each case, every list item is enclosed in <li></li> tags.

A paragraph may not contain lists.

<ul>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Unordered List Example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <header>
        <h1>Today's shopping list</h1>
      </header>
      <ul>
        <li>Meat</li>
        <li>Cheese</li>
        <li>Vegetables</li>
        <li>Water</li>
        <li>Bin bags</li>
      </ul>
    </main>
  </body>
</html>

ul1

<ol>

This element supports the following particular attributes:

Name Value Description

reversed

descending list order

start

number

start value

type

1, A, a, I, i

list marker

Ordered list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Ordered List Example</title>
    <meta charset=UTF-8>
    <style>
      #l3 {
        list-style-type: upper-roman;
      }
    </style>
  </head>
  <body>
    <main>
      <header>
        <h1>Today's shopping lists</h1>
      </header>
      <ol style="float: left">
        <li>Meat</li>
        <li>Cheese</li>
        <li>Vegetables</li>
        <li>Water</li>
        <li>Bin bags</li>
      </ol>
      <ol style="float: left" reversed>
        <li>Meat</li>
        <li>Cheese</li>
        <li>Vegetables</li>
        <li>Water</li>
        <li>Bin bags</li>
      </ol>
      <ol id=l3 style="float: left" start=3 type=A>
        <li>Meat</li>
        <li>Cheese</li>
        <li>Vegetables</li>
        <li>Water</li>
        <li>Bin bags</li>
      </ol>
    </main>
  </body>
</html>

The style attribute value of float: left means that the list is floated left. As a result, the following element is placed right to the list instead of underneath. Remove the three style attributes and compare the result.

Nested lists

We can nest lists. This means we can have a list inside a list inside a list inside a list …​ as many times as we want. The only thing we need to watch is the correct nesting, i.e. we need to close the last opened list tag before we close the second last etc.

Example:

Nested list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Nested list example</title>
    <meta charset=UTF-8>
    <style>
      body {
        background-color: black;
        color:            gold;
      }

      main {
        position:  relative;
        width:     550px;
        height:    230px;
        animation: move 30s linear 0s infinite alternate;
      }

      /* cf. http://www.w3schools.com/css/tryit.asp?filename=trycss3_animation5 */
      @keyframes move {
        0% {
          background-color: blue;
          left:             0px;
          top:              0px;
        }
        25% {
          background-color: white;
          left:             550px;
          top:              0px;
        }
        50% {
          background-color: red;
          left:             550px;
          top:              230px;
        }
        75% {
          background-color: darkgray;
          left:             0px;
          top:              230px;
        }
        100% {
          background-color: red;
          left:             0px;
          top:              0px;
        }
      }
    </style>
  </head>
  <body>
    <main>
      <ul type=A>
        <li>Human life has several purposes:
          <ol>
            <li>To learn:
              <ol type=a>
                <li>HTML</li>
                <li>CSS</li>
                <li>JavaScript</li>
                <li>PHP</li>
                <li>MySQL</li>
              </ol>
            </li>
            <li>To have fun.</li>
            <li>To become a WMOTU.</li>
            <li>But the mother of all purposes is to become the ultimate problem
              solver.
            </li>
          </ol>
        </li>
        <li>Let's do it!</li>
      </ul>
    </main>
  </body>
</html>

Like the animation? We’ll do plenty of these in section Transformation and animation.

<dl>
The dl element represents an association list consisting of zero or more name-value groups (a description list). A name-value group consists of one or more names (dt elements) followed by one or more values (dd elements), ignoring any nodes other than dt and dd elements. Within a single dl element, there should not be more than one dt element for each name.
dl1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Description List Example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <dl>
        <dt>HTML5</dt>
        <dd>HTML5 is a markup language used for structuring and presenting content for the
          World Wide Web and a core technology of the Internet (cf.
          <a href=http://en.wikipedia.org/wiki/HTML5>http://en.wikipedia.org/wiki/HTML5</a>).
        </dd>
        <dt>CSS3</dt>
        <dd>Cascading Style Sheets (CSS) is a style sheet language used for describing the
          presentation semantics (the look and formatting) of a document written in a
          markup language. Its most common application is to style web pages written in
          HTML and XHTML, but the language can also be applied to any kind of XML
          document, including plain XML, SVG and XUL (cf. <a
            href=https://en.wikipedia.org/wiki/CSS>
            https://en.wikipedia.org/wiki/CSS</a>).
        </dd>
        <dt>JavaScript</dt>
        <dd>JavaScript (JS) is an interpreted computer programming language. As part of
          web browsers, implementations allow client-side scripts to interact with the
          user, control the browser, communicate asynchronously, and alter the document
          content that is displayed. It has also become common in server-side
          programming, game development and the creation of desktop applications
          (cf. <a href=https://en.wikipedia.org/wiki/JavaScript>https://en.wikipedia
            .org/wiki/JavaScript</a>).
        </dd>
        <dt>PHP5</dt>
        <dd>PHP is a server-side scripting language designed for web development but
          also used as a general-purpose programming language. PHP is now installed on
          more than 244 million websites and 2.1 million web servers (cf. <a
            href=https://en.wikipedia.org/wiki/PHP5>
            https://en.wikipedia.org/wiki/PHP5</a>).
        </dd>
      </dl>
    </main>
  </body>
</html>

4.1.10. <a>

The <a> tag defines a hyperlink, which is used to link from one page to another.

The most important attribute of the <a> element is the href attribute, which indicates the link’s destination.

By default, links will appear as follows in all browsers:

  1. unvisited link

  2. visited link

  3. active link

This element supports the following particular attributes:

Name Value Description

download

filename

target will be downloaded instead of opened. If filename is omitted it will be saved under the original filename. This works only for files located on the same server than the current page.

href

URL

URL of the page

hreflang

language_code

language of the linked document

media

media_query

the medium that the document is optimized for

rel

alternate, author, bookmark, help, license , next, nofollow, noreferrer, noopener, prefetch, prev, search, tag

Relationship between the current and the linked document. rel=noreferrer will prevent the destination page from learning which page you came from. See developer.mozilla.org/en-US/docs/Web/HTML/Link_types for an excellent overview of all link types. Why are noreferrer or noopener important? See mathiasbynens.github.io/rel-noopener.

target

_blank`, _parent, _self, _top framename

where to open the linked document

Here is an example that illustrates different values for the href attribute:

a1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>This is a simple hyperlink example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <header>
      <h1>Welcome to <a href=http://www.ltam.lu target=_blank>LAM</a>.</h1>
    </header>
    <main>
      <a href=a1contact.html>Contact us</a>
    </main>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>This is a simple hyperlink example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <a href="http://www.ltam.lu/index.php?portal=26" target=_blank>How to find us</a>
      <a href=a1.html>Home</a>
      <a
        href="mailto:gilles.everling@education.lu?cc=everybody@world.com&bcc=spy@NSA.gov&subject=Top%20Secret%20Message&body=This%20is%20the%20message%20body">Email the author</a>
    </main>
  </body>
</html>

Note that we need to provide the correct path to the file that the hyperlink is linking to via the href attribute. If we are linking to a page on the Internet, we need to specify the complete Unified Resource Locator (URL, cf. en.wikipedia.org/wiki/URL), which consists of the protocol, a colon, two slashes, a host, normally given as a domain name but sometimes as a literal Internet Protocol (IP) address, optionally a port number and finally the full path of the resource. The protocol used to access Internet pages is called Hypertext Transfer Protocol (HTTP).

If we link to a file within our web site, we use a relative URL, as shown in line 12 of a1.html. If we link to a file on another server, we need to provide an absolute URL as shown in line 9.

If we want to allow the user to send an email by clicking on a hyperlink, we use mailto, as shown in lines 11 to 12 of a1contact.html. Note that we can pass additional parameters such as carbon copy (cc) and black carbon copy (bcc) as well as the subject and body. We put a ? in front of the parameters. We assign a value to a parameter using = and each parameter/value pair is separated by a &. Also note that we need to encode spaces using %20, which is the corresponding hexadecimal (32 decimal) ASCII code (cf. www.w3schools.com/charsets/ref_html_ascii.asp). The example above gives a validation error because of the new lines in the href attribute string. The whole string should be in a single line, but this would not allow the clean printing of the code in the book. See also stackoverflow.com/questions/10356329/mailto-link-multiple-body-lines.

A hyperlink can also point to another place on the same page. For this purpose, we can use the id attribute on any tag. This is useful if our page contains a huge amount of content and we want to give the user the option to jump directly to a specific location on the page, instead of having to scroll down manually.

To nest a hyperlink inside another hyperlink we can use the <object> tag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>This is a nested hyperlink example</title>
    <meta charset=UTF-8>
    <style>
      main > a > div {
        margin:           10px;
        padding:          20px;
        background-color: greenyellow;
      }

      main > a > div > object > a {
        background-color: yellowgreen;
      }
    </style>
  </head>
  <body>
    <main>
      <a href=https://students.btsi.lu target=_blank>
        <div>students.btsi.lu (<object type=text/html><a
                  href=https://students.btsi.lu/evegi144/WAD/WAD.html target=_blank>WAD</a>)
          </object>
        </div>
      </a>
    </main>
  </body>
</html>

4.1.11. <img>

The <img> tag is used to insert an image. This element supports the following particular attributes:

Name Value Description

alt

text

alternate text for image, required for successful validation

crossorigin

anonymous, use-credentials

use third-party site images with canvas (cf. developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes)

height

pixels

image height

ismap

ismap

image is a server-side map (cf. www.w3schools.com/tags/att_img_ismap.asp)

src

URL

image URL

usemap

#mapname

image is a client-side map (cf. www.w3schools.com/tags/att_img_usemap.asp

width

pixels

image width

The alt attribute is required for successful validation. It can be used by screen readers, search engines and others. It will also be displayed by the browser in case the image cannot be displayed.

We should always specify the exact width and height of an image, as they allow the browser to allocate the space required to display the image before the image is loaded. Without them, the browser will have to adjust the page layout after the image has finished loading.

We do not use the width and height attributes to change the size of an image, as the full image will still be loaded by the browser. In order to produce a thumbnail for instance, we use a drawing program such as GIMP (www.gimp.org) or an online editor, e.g. pixlr.com/editor (cf. Image resizing). Be careful to specify the correct path and name of the image. Use .. to go up to the parent folder and / to separate folder and file names. We can embed images inside hyperlinks, like so:

img1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Image example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <a href="https://www.iconfinder.com/icons/131462/automatic_automatic_machine_automaton_dog_machine_machine_gun_robot_shadow_with_icon#size=512">
        <img src=dog_robot_with_shadow.png width=512 height=512
           alt="https://www.iconfinder.com/icons/131462/automatic_automatic_machine_automaton_dog_machine_machine_gun_robot_shadow_with_icon#size=512">
      </a>
    </main>
  </body>
</html>

Notice that we have to use quotes here for the value of the href and alt attributes, as they span several lines. The validator won’t like this.

Image formats

The three main image formats used on the Web are JPEG, PNG and GIF. There is a new kid on the block, called Scalable Vector Graphics (SVG), which requires a much deeper understanding to handle but offers a number of advantages, that we’ll look into in section SVG.

The key characteristics of the main image formats are summarized in the following table:

Format Compression Colors Transparency Animation

PNG

lossless

256 (8 bit), 16.7 million (24 bit) or 4.3 billion (32 bit)

yes

no

JPEG

lossy

16.7 million (24 bit)

no

no

GIF

lossless

256 (8 bit)

yes

yes

If you don’t need animation, PNG is the preferred format, particularly for web graphics.

If you want to create animated GIFs, take a loot at GifCam (blog.bahraniapps.com/gifcam), which allows you create and edit screencasts and save them as compact GIF images that can be easily embedded in your HTML5, like so:

Image resizing

Resizing an image with GIMP is easy:

GIMP1
GIMP2

After you’ve resized the image, export it under a new name:

GIMP3
Adding transparency

We can either use a program such as Online Image Editor (cf. www.online-image-editor.com/help/transparency) or use GIMP (www.bogotobogo.com/Gif/gimp-tutorial-transparency.php).

<map>

The <map> tag is used to define a client-side image-map. See www.w3schools.com/tags/att_img_usemap.asp for the details.

Here is a simple example application:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Image map example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <img src=dog_robot_with_shadow.png width=512 height=512 usemap=#dogmap
         alt="https://www.iconfinder.com/icons/131462#size=512">
      <map name=dogmap>
        <area shape=rect coords=10,0,250,150 href=map1head.html alt=Head>
        <area shape=rect coords=50,151,400,340 href=map1body.html alt=Body>
        <area shape=rect coords=0,350,512,512 href=map1leg.html alt=Leg>
      </map>
    </main>
  </body>
</html>
Logo creation

With Inkscape we can create a logo very easily.

inkscape1
inkscape1a
inkscape1b
inkscape2
inkscape2a
inkscape3
inkscape4
inkscape5
inkscape6

Export the bitmap using Ctrl+Shift+E and select page as export area.

inkscape7

4.1.12. <nav>

This element is used to create the main navigation on a site:

navigation1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Navigation</title>
    <meta charset=UTF-8>
    <link href=navigation1.css rel=stylesheet>
  </head>
  <body>
    <header>
      <h1>Navigation</h1>
      <nav>
        <ul>
          <li><a href=#>Home</a></li>
          <li><a href=#>About</a></li>
          <li><a href=#>Team</a></li>
          <li><a href=#>Shareholders</a></li>
          <li><a href=#>Contact</a></li>
        </ul>
      </nav>
    </header>
  </body>
</html>

Here the CSS3 file (don’t worry, we’ll address that topic in the next chapter):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
body {
  background-color: lightseagreen;
}

h1 {
  margin: 0;
}

ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

li {
  display: inline;
}

4.1.13. <main>

The main element represents the main content section of the body of a document or application. The main content section consists of content that is directly related to or expands upon the central topic of a document or central functionality of an application.

Note: the main element is not sectioning content and has no effect on the document outline.

The main content section of a document includes content that is unique to that document and excludes content that is repeated across a set of documents such as site navigation links, copyright information, site logos and banners and search forms (unless the document or applications main function is that of a search form).

Authors MUST NOT include more than one main element in a document.

Authors MUST NOT include the main element as a child of an article, aside, footer, header or nav element.

4.1.14. <section>

The section element represents a generic section of a document or application. A section, in this context, is a thematic grouping of content, typically with a heading.

Example:

section1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Section example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <header>
    </header>
    <main>
      <section>
        <h1>Section 1</h1>
        This is a section with some content.
      </section>
      <section>
        <h1>Section 2</h1>
        This is another section with some content.
      </section>
    </main>
  </body>
</html>

The footer element represents a footer for its nearest ancestor sectioning content or sectioning root element. A footer typically contains information about its section such as who wrote it, links to related documents, copyright data, and the like.

When the footer element contains entire sections, they represent appendices, indexes, long colophons, verbose license agreements, and other such content.\end{quote}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Footer example</title>
    <meta charset=utf-8>
  </head>
  <body>
    <header>
      <nav></nav>
    </header>
    <main>

    </main>
    <footer>&copy; 2014 WMOTU</footer>
  </body>
</html>

4.1.16. <article>

The article element represents a complete, or self-contained, composition in a document, page, application, or site and that is, in principle, independently distributable or reusable, e.g. in syndication. This could be a forum post, a magazine or newspaper article, a blog entry, a user-submitted comment, an interactive widget or gadget, or any other independent item of content.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Article example</title>
    <meta charset=utf-8>
  </head>
  <body>
    <main>
      <article>
        <h1>HTSTA</h1>
        <p>HTSTA is the first step to a fulfilling web developer career.</p>
      </article>
    </main>
  </body>
</html>

4.1.17. <aside>

The aside element represents a section of a page that consists of content that is tangentially related to the content around the aside element, and which could be considered separate from that content. Such sections are often represented as sidebars in printed typography.

The element can be used for typographical effects like pull quotes or sidebars, for advertising, for groups of nav elements, and for other content that is considered separate from the main content of the page.

The link above provides usage examples.

4.1.18. <div>

The div element has no special meaning at all. It represents its children. It can be used with the class, lang, and title attributes to mark up semantics common to a group of consecutive elements.

Note: Authors are strongly encouraged to view the div element as an element of last resort, for when no other element is suitable. Use of more appropriate elements instead of the div element leads to better accessibility for readers and easier maintainability for authors.

4.1.19. <q>

To mark up a short quotation, we use the <q> tag. This element has one special attribute, cite, that can be used to specify the source URL of the quote.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Quote example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      George Orwell's <q>Politics and the English Language</q>  from 1946
    </main>
  </body>
</html>

4.1.20. <blockquote>

To mark up a longer quotation from another source, use the <blockquote> tag:

blockquote1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Blockquote example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      George Orwell, in his <q>Politics and the English Language</q> from 1946,
      provided the following insight:
      <blockquote>
        Political language… is designed to make lies sound truthful and murder
        respectable,
        and to give an appearance of solidity to pure wind.
      </blockquote>
    </main>
  </body>
</html>

4.1.21. Firefox console and Firebug

By pressing Shift+F2 you open the Firefox console, which is a great tool to analyse web pages:

FirefoxConsole1

The console tab displays information, warning and error messages and will be one of our most important development tools throughout our web app development journey. The inspector enables us to take a closer look at the styling of a particular element. The debugger will be very helpful to track errors in our JavaScript adventures. The style editor permits the real time changing of the current web page’s styles. Try it! The profiler serves to analyse the performance of our app and detect bottleneck. The network tab displays detailed information about what happens on the network. This will be very helpful once we start using HTTP forms and Ajax.

By pressing F12 you open Firebug, if this plugin is installed in your Firefox browser. If not, you can install it by selecting Tools  Add-ons. Search for Firebug and install it.

Firebug provides even more advanced analysis functionality than the console.

Style sheet

We have already seen at the beginning of this chapter an example of an external style sheet inclusion. We just have to include a link with the correct relationship attribute in the head of our document:

1
<link rel=stylesheet href=style.css>
Favicon
favicon1
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Favicon example 1</title>
    <meta charset=UTF-8>
    <link rel=icon href=favicon.ico>
  </head>
  <body>
    <main>
    </main>
  </body>
</html>

We can even have animated favicons, at least in Firefox:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Favicon example 2</title>
    <meta charset=UTF-8>
    <link rel=icon href=bear.gif type=image/gif>
  </head>
  <body>
    <main>
    </main>
  </body>
</html>

Icon files can be 16×16, 32×32, 48×48, or 64×64 pixels in size, and 8-bit, 24-bit, or 32-bit in color depth.

4.1.24. <meta>

The <meta> tag is used to provide metadata, i.e. data that describes the document. This data is not displayed on the page, but can be processed by the browser, search engines or other web services (cf. developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML).

This element supports the following particular attributes:

Name Value Description

charset

character set

character encoding for the document, we use utf-8

content

text

value associated with the http-equiv or name attribute

http-equiv

content-type, default-style, refresh

create HTTP header for content attribute

name

application-name, author, description, generator, keywords

name for the metadata

We use the charset attribute to specify the character encoding of our document. This should be set to Unicode, i.e. utf-8, as it allows us to use language specific characters such as é and ä. A list of all available character encodings can be found at www.iana.org/assignments/character-sets/character-sets.xhtml.

Before the advent of HTML5, http-equiv was used to set the character encoding, but no more. The value default-style can be used to specify the preferred stylesheet from a selection of link or style elements in case there are several in your document. The value refresh can be used to specify after how many seconds a page should be automatically refreshed (i.e. reloaded) or if it should redirect to another page. This can be useful for a site whose content changes rapidly and where you don’t want to use JavaScript. For instance, let’s assume you have a new web site and you want users to be automatically transferred from your old site to the new one. On your old site, you’d have the following main page: students.btsi.lu/evegi144/WAD/HTML5/metaredirect1.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Redirection example</title>
    <meta charset=UTF-8>
    <meta http-equiv=refresh content="3; url=metaredirect2.html">
  </head>
  <body>
    <main>
      <header>
        <h1>You'll be redirected to my new site in 3 seconds.</h1>
      </header>
    </main>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Redirection example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <header>
        <h1>Welcome to my new site.</h1>
        Hope you like it!
      </header>
    </main>
  </body>
</html>

The name attribute can take one of the following values:

Value Description

application-name

name of the Web application

author

document author

description

description of the page content, can be used by search engines

generator

if the page was generated by a specific software

keywords

comma-separated list of keywords relevant to the page content targeted at search engines

Let’s look at an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Meta name usage example</title>
    <meta charset=UTF-8>
    <meta name=application-name content="Meta name usage example">
    <meta name=author content="Gilles Everling">
    <meta name=description content="Meta name usage">
    <meta name=keywords content=meta,name,HTML5>
  </head>
  <body>
    <main>
      <header>
        <h1>A simple application of the <code>meta name</code> attribute.</h1>
      </header>
    </main>
  </body>
</html>

4.1.25. <table>

Tables are used to display tabular data, for instance the current national football league rankings. HTML5 tables must not be used for layout purposes. We’ll look at a number of appropriate ways to create a tabular layout later on.

A table consists of rows (<tr>) and cells (<td>). Thus, a Tic Tac Toe table would look like this:

table1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>A simple Tic Tac Toe table</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <table>
        <tr>
          <td>X</td>
          <td>X</td>
          <td>O</td>
        </tr>
        <tr>
          <td>X</td>
          <td>X</td>
          <td>O</td>
        </tr>
        <tr>
          <td>O</td>
          <td>O</td>
          <td>X</td>
        </tr>
      </table>
    </main>
  </body>
</html>

The <table> tag supports only one attribute, border. It can have no value, "" or 1. In each of these cases, the table and each cell will have a border 1 pixel wide. Without this attribute the table and cells will have no border.

In most cases it is useful to have a table header, which contains the name or description of the data for each column. We may also need a table footer (cf. www.w3.org/TR/html51/tabular-data.html#the-tfoot-element). For this purpose, we split the table into a head, a body and a footer part, using the <thead>, <tbody> and <tfoot> tags. Header cells are displayed centered and bold using the <th> tag instead of <td>. We can add a caption using the `<caption> tag. Here’s an example:

table2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>A simple table with caption, header, body and footer</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <table border>
        <caption>This term's grades</caption>
        <thead>
          <tr>
            <th>Subject</th>
            <th>Grade</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>SYSEX1</td>
            <td>51</td>
          </tr>
          <tr>
            <td>MATHE1</td>
            <td>45</td>
          </tr>
        </tbody>
        <tfoot>
          <tr>
            <td>Average</td>
            <td>48</td>
          </tr>
        </tfoot>
      </table>
    </main>
  </body>
</html>

We can have cells span several columns and/or several rows, using the colspan and rowspan attributes. Example:

table3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>colspan and rowspan example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <table border>
        <thead>
          <tr>
            <th>Name</th>
            <th>Village</th>
            <th colspan=2>Phone numbers</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>Asterix</td>
            <td rowspan=2>Gaul</td>
            <td>123 456</td>
            <td>621 123 456</td>
          </tr>
          <tr>
            <td>Obelix</td>
            <td>123 457</td>
            <td>621 123 457</td>
          </tr>
        </tbody>
      </table>
    </main>
  </body>
</html>

The <th> and <td> tags can have a headers attribute. It links a cell to a given header cell. For this to work, the header cell needs an id. This has no impact on the page display, but may be used by screen readers. See www.w3schools.com/tags/att_th_headers.asp for an example.

The <th> tag can have a scope attribute, which indicates whether a header cell is a header for a column, row, or group of columns or rows. See www.w3schools.com/tags/att_th_scope.asp and developer.mozilla.org/en-US/docs/Learn/HTML/Tables/Advanced.

For formatting purposes, we can use the <colgroup> tag, see www.w3schools.com/tags/tag_colgroup.asp.

Soon, we’ll see how we can style tables with CSS. Here’s a little foretaste:

table4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
<!DOCTYPE html>
<html lang=de>
  <head>
    <title>HTML and CSS Table Demo</title>
    <meta charset=UTF-8>
    <style>
      body {
        background: radial-gradient(rgb(200, 50, 20), rgb(255, 255, 60), rgb(255, 50, 20),
        black) no-repeat fixed;
        overflow:   hidden;
      }

      h1 {
        font:        6em impact fantasy;
        text-shadow: 3px 3px white;
        animation:   introAnimation 7s;
        -webkit-animation: introAnimation 7s;
        overflow:    hidden;
        text-align:  center;
        position:    absolute;
      }

      @keyframes introAnimation {
        0% {
          top:       400px;
          font-size: 0.1em;
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(720deg);
          top:       0;
        }
      }

      @-webkit-keyframes introAnimation {
        0% {
          top:       400px;
          font-size: 0.1em;
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(720deg);
          top:       0;
        }
      }

      table {
        position:       absolute;
        overflow:       hidden;
        top:            200px;
        left:           0;
        color:          white;
        border:         2px ridge red;
        border-spacing: 0;
        transition:     left 5s;
        text-shadow:    1px 1px black;
      }

      table:hover {
        color: gold;
        left:  5000px;
      }

      table caption {
        font-size: 2em;
      }

      th {
        background-color: lightblue;
        text-align:       left;
        padding:          5px;
        margin:           0;
      }

      td {
        padding: 5px;
      }

      tr {
        padding: 5px;
      }

      tr:nth-of-type(odd) {
        background-color: green;
      }
    </style>
  </head>
  <body>
    <header>
      <h1>T0IF HTSTA</h1>
    </header>
    <main>
      <table>
        <caption>Nationale Fußballtabelle</caption>
        <thead>
          <tr>
            <th></th>
            <th>Rang</th>
            <th>Mannschaft</th>
            <th>Punkte</th>
            <th>Tore A</th>
            <th>Tore B</th>
            <th>Diff.</th>
            <th>Spiele</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td rowspan=14 style="padding: 0; transform: rotate(-90deg);
            font-size: 3em;">22.5.13
            </td>
            <td>1.</td>
            <td>Fola</td>
            <td>53</td>
            <td>58</td>
            <td>20</td>
            <td>38</td>
            <td>24</td>
          </tr>
          <tr>
            <td>2.</td>
            <td>F91</td>
            <td>49</td>
            <td>45</td>
            <td>17</td>
            <td>28</td>
            <td>24</td>
          </tr>
          <tr>
            <td>3.</td>
            <td>Jeunesse</td>
            <td>47</td>
            <td>50</td>
            <td>25</td>
            <td>25</td>
            <td>24</td>
          </tr>
          <tr>
            <td>4.</td>
            <td>RM Hamm Benfica</td>
            <td>42</td>
            <td>47</td>
            <td>34</td>
            <td>13</td>
            <td>24</td>
          </tr>
          <tr>
            <td>5.</td>
            <td>Déifferdeng03</td>
            <td>41</td>
            <td>46</td>
            <td>31</td>
            <td>15</td>
            <td>24</td>
          </tr>
          <tr>
            <td>6.</td>
            <td>Gréiwemaacher</td>
            <td>36</td>
            <td>40</td>
            <td>32</td>
            <td>8</td>
            <td>24</td>
          </tr>
          <tr>
            <td>7.</td>
            <td>Kanech</td>
            <td>34</td>
            <td>38</td>
            <td>33</td>
            <td>5</td>
            <td>24</td>
          </tr>
          <tr>
            <td>8.</td>
            <td>Käerjéng</td>
            <td>31</td>
            <td>42</td>
            <td>48</td>
            <td>-6</td>
            <td>24</td>
          </tr>
          <tr>
            <td>9.</td>
            <td>RFCUL</td>
            <td>30</td>
            <td>38</td>
            <td>37</td>
            <td>1</td>
            <td>24</td>
          </tr>
          <tr>
            <td>10.</td>
            <td>Wolz 71</td>
            <td>30</td>
            <td>39</td>
            <td>61</td>
            <td>-22</td>
            <td>24</td>
          </tr>
          <tr>
            <td>11.</td>
            <td>Progrès Nidderkuer</td>
            <td>24</td>
            <td>26</td>
            <td>41</td>
            <td>-15</td>
            <td>24</td>
          </tr>
          <tr>
            <td>12.</td>
            <td>Etzella</td>
            <td>24</td>
            <td>35</td>
            <td>55</td>
            <td>-20</td>
            <td>24</td>
          </tr>
          <tr>
            <td>13.</td>
            <td>Peiteng</td>
            <td>14</td>
            <td>20</td>
            <td>50</td>
            <td>-30</td>
            <td>24</td>
          </tr>
          <tr>
            <td>14.</td>
            <td>Kayl/Teiteng Union05</td>
            <td>12</td>
            <td>27</td>
            <td>67</td>
            <td>-40</td>
            <td>24</td>
          </tr>
        </tbody>
      </table>
    </main>
    <script>
      document.querySelector("h1").style.left = (window.innerWidth - 566) / 2 + "px";
      addEventListener('resize', () => {
        document.querySelector("h1").style.left = (window.innerWidth - 566) / 2 + "px";
      });
    </script>
  </body>
</html>

4.1.26. Forms

HTML forms (www.w3.org/TR/html51/semantics.html#forms) are used to pass data to a server. They are the building blocks that allow the user to provide data to our application. When you use a search engine or buy something in an online shop, you use forms to enter your information.

An HTML form can consist of different input elements such as text fields, check boxes, radio-buttons, submit buttons, selection lists, text areas, labels etc.

Here’s the full list of form tags to be used within <form>:

Tag Description

<input>

single line text field

<textarea>

multi line text area

<label>

label, i.e. a text to be displayed next to a form element

<fieldset>

groups related elements

<legend>

caption (short description) for a field set

<select>

drop-down list

<optgroup>

group of related options in a drop-down list

<option>

option in a drop-down list

<button>

clickable button

<datalist>

option list

<keygen>

key-pair generator field

<output>

result of a calculation

All form elements are enclosed within the <form> tag. Here’s a simple example:

HTML forms1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>A first form example using post</title>
    <meta charset=utf-8>
  </head>
  <body>
    <main>
      <form method=post action=forms1.php>
        First name: <input name=first_name required><br>
        Last name: <input name=last_name required><br>
        <input type=submit>
      </form>
    </main>
  </body>
</html>

When you submit your input, the forms1.php script gets executed on the server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>A first form example using post</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <?php
        if (isset($_POST['first_name'], $_POST['last_name']))
          echo '<p>Hi ' . $_POST['first_name'] . ' ' . $_POST['last_name'] . '</p>';
      ?>
    </main>
  </body>
</html>

Don’t worry about the PHP part, we’ll get into that later. Our example uses two of the most important <form> tag attributes: action and method. The former specifies the script on the server that should receive the form data. The latter indicates the method that should be used to send the data to the server, either GET, which sends the data via the URL or POST, which sends the data embedded within the HTTP request. Run our first form example, open the Firefox console and select the Network tab. Now enter your first and last names and submit the form. You should see something similar to this:

forms1

Now click on the forms1.php line and select the Params tab on the right:

forms2

As you can see, your input has been sent as form data, i.e. embedded inside the form.

Now let’s check what happens if we use the GET method: students.btsi.lu/evegi144/WAD/HTML5/forms2.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>A first form example using get</title>
    <meta charset=utf-8>
  </head>
  <body>
    <main>
      <form action=forms2.php>
        First name: <input name=first_name required><br>
        Last name: <input name=last_name required><br>
        <input type=submit>
      </form>
    </main>
  </body>
</html>

When you submit your input, the forms2.php script gets executed on the server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>A first form example using get</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <?php
        if (isset($_GET['first_name']) && isset($_GET['last_name']))
          echo '<p>Hi ' . $_GET['first_name'] . ' ' . $_GET['last_name'] . '</p>';
      ?>
    </main>
  </body>
</html>

If you perform the same network analysis as before, you get this:

forms3

You should notice two changes:

  1. The URL contains a ? and a & as well as the data you entered in the form.

  2. The parameter tab says that the data has been sent as query string, i.e. as part of the URL and not embedded as form data.

This means that the form data is visible to everyone and can be easily intercepted, whereas for the POST method this is a little bit more difficult. GET submissions can be bookmarked and URLs are usually stored in log files on the server, whereas the body of HTTP requests usually is not and can also not be bookmarked. We therefore prefer to use the POST method.

Here is an overview of all the attributes specific to the <form> tag:

Attribute Value Description

accept-charset

character set

character encoding to be used for form submission

action

URL

script to receive the form data

autocomplete

on/off

turn autocomplete on or off

enctype

application/x-www-form-urlencoded, multipart/form-data, text/plain

how the data should be encoded (only for POST method)

method

GET or POST

HTTP method to be used

name

text

name of the form

novalidate

the form should not be validated upon submission

target

_blank, _self, _parent, _top

display response from server in a new, the current, the parent or the top window/tab

Given the excellent documentation on W3Schools regarding all form elements, I will not repeat the details here but instead refer you to their site www.w3schools.com/html/html_forms.asp. Go through the examples and get a feel for forms. We’ll use them throughout our Web app development journey.

Here is a more complete example:

HTML forms3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>A more advanced form example</title>
    <meta charset=utf-8>
    <style>
      form {
        width:        350px;
        margin-left:  auto;
        margin-right: auto;
      }

      form label {
        float:         left;
        width:         150px;
        text-align:    right;
        padding-right: 10px;
        margin-top:    10px;
      }

      form input {
        margin-top:    10px;
        text-shadow:   1px 1px 1px white;
        border-radius: 5px;
      }

      form input:focus {
        background-color: yellow;
      }

      form input[type=submit], form input[type=button], form input[type=reset] {
        background:  linear-gradient(to bottom right, yellow, red);
        margin-left: 160px;
        width:       190px;
      }

      form input[type=submit]:focus, form input[type=button]:focus,
      form input[type=reset]:focus {
        border: 2px solid grey;
      }

      form input::-moz-focus-inner {
        border: 0;
      }

      form legend {
        font-weight: bold;
      }

      form select {
        border-radius: 5px;
      }

      form select optgroup {
        background-color: yellow;
      }

      form select optgroup option {
        background-color: greenyellow;
      }
      form fieldset {
        border: 1px solid black;
      }
    </style>
  </head>
  <body>
    <main>
      <form method=post>
        <fieldset>
          <legend>Personal data</legend>
          <label for=first_name>First name:</label>
          <input id=first_name list=names name=first_name placeholder=Pitty required autofocus>
          <datalist id=names>
            <option>Donald</option>
            <option>Mickey</option>
          </datalist><br>
          <label>Last name:</label>
          <input name=last_name required><br>
          <label>Password:</label>
          <!-- oncopy, onpaste and oncut are not part of the HTML5 standard,
          so they should not be used! -->
          <input type=password name=password required oncopy='return false;'
               onpaste='return false;' oncut='return false;'><br>
          <label>Email:</label>
          <input type=email name=email required><br>
          <label></label> <!-- Just used for layout purposes. -->
          <input type=radio name=sex value=male checked>Male<br>
          <label></label>
          <input type=radio name=sex value=female>Female<br>
          <label></label>
          <input type=checkbox name=bike value=Bike>I have a bike<br>
          <label></label>
          <input type=checkbox name=car value=Car>I have a car
        </fieldset>
        <fieldset>
          <legend>Other data</legend>
          <select>
            <optgroup label="Swedish Cars">
              <option value=volvo>Volvo</option>
              <option value=saab selected>Saab</option>
            </optgroup>
            <optgroup label="German Cars">
              <option value=mercedes>Mercedes</option>
              <option value=audi>Audi</option>
            </optgroup>
          </select>
          <textarea rows=3 cols=50 name=my_area maxlength=500
                placeholder="Short description of yourself (max. 500 chars)">
          </textarea><br>
          <label>Color:</label>
          <input type=color name=color><br>
          <label>Number (1-10):</label>
          <input type=number name=number min=1 max=10><br>
          <label>Number range:</label>
          <input type=range name=range min=1 max=100 value=50 step=5><br>
        </fieldset>
        <input type=submit value=Submit>
        <input type=reset>
      </form>
      <form oninput="x.value = parseInt(a.value) + parseInt(b.value)">0
        <input type=range id=a value=50>
        + <input type=number id=b value=50>
        =
        <output name=x for="a b"></output>
      </form>
    </main>
  </body>
</html>
<input>
The input element represents a typed data field, usually with a form control to allow the user to edit the data.

Excellent examples can be found at www.w3schools.com/tags/tag_input.asp.

See www.w3schools.com/html/html_form_attributes.asp for details on input attributes.

To capture photos using the user’s camera you can use the capture attribute, like so:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang=en>
  <head>
    <meta charset=UTF-8>
    <title>Camera capture example</title>
  </head>
  <body>
    <form>
      <input type=file accept=image/* capture>
    </form>
  </body>
</html>

Please note that you can prevent the copying, pasting and cutting of input field contents by setting the corresponding event handlers (cf. Events) as shown in the password input in the example above.

<textarea>

The textarea element represents a multiline plain text edit control for the element’s raw value. The contents of the control represent the control’s default value.

The raw value of a \texttt{textarea} control must be initially the empty string.

<label>
The label element represents a caption in a user interface. The caption can be associated with a specific form control, known as the label element’s labeled control, either using the for attribute, or by putting the form control inside the label element itself.
<fieldset>

The fieldset element represents a set of form controls optionally grouped under a common name.

The name of the group is given by the first legend element that is a child of the fieldset element, if any. The remainder of the descendants form the group.

<legend>
The legend element represents a caption for the rest of the contents of the legend element’s parent fieldset element, if any.
<select>

The select element represents a control for selecting amongst a set of options.

The multiple attribute is a boolean attribute. If the attribute is present, then the select element represents a control for selecting zero or more options from the list of options. If the attribute is absent, then the select element represents a control for selecting a single option from the list of options.

The size attribute gives the number of options to show to the user. The size attribute, if specified, must have a value that is a valid non-negative integer greater than zero.

The display size of a select element is the result of applying the rules for parsing non-negative integers to the value of element’s size attribute, if it has one and parsing it is successful. If applying those rules to the attribute’s value is not successful, or if the size attribute is absent, then the element’s display size is 4 if the element’s multiple content attribute is present, and 1 otherwise.

The list of options for a select element consists of all the option element children of the select element, and all the option element children of all the optgroup element children of the select element, in tree order.

<optgroup>
The optgroup element represents a group of option elements with a common label.
<option>
The option element represents an option in a select element or as part of a list of suggestions in a datalist element.
<button>
The button element represents a button labeled by its contents.
<datalist>
The datalist element represents a set of option elements that represent predefined options for other controls.
<keygen>
The keygen element represents a key pair generator control. When the control’s form is submitted, the private key is stored in the local keystore, and the public key is packaged and sent to the server.
<output>
The output element represents the result of a calculation or user action.

4.1.27. Block vs inline elements

A block element is an element that takes up the full width available, and has a line break before and after it.

Examples of block elements:

  • <h1>

  • <p>

  • <div>

An inline element only takes up as much width as necessary, and does not force line breaks.

Examples of inline elements:

  • <span>

  • <a>

display1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Inline vs block display example</title>
    <meta charset=utf-8>
    <style>
      main {
        border:  2px solid red;
        padding: 5px;
      }

      h1 {
        border:  1px inset blue;
        padding: 3px;
      }

      span {
        border: 1px dashed green;
      }

      .inlineList {
        display: inline;
      }
    </style>
  </head>
  <body>
    <main>
      <h1>This is a heading level 1, a <strong>block</strong> element.</h1>
      This is a <span>span</span>, which is an <strong>inline</strong> element.
      <p>Sometimes it is useful to change the default display settings. For
      example, we might want list items to be stacked horizontally instead of
      vertically. So instead of this:
      </p>
      <ul>
        <li>Item1</li>
        <li>Item2</li>
        <li>Item3</li>
        <li>Item4</li>
      </ul>
      We might prefer this:
      <ul>
        <li class=inlineList>Item1</li>
        <li class=inlineList>Item2</li>
        <li class=inlineList>Item3</li>
        <li class=inlineList>Item4</li>
      </ul>
    </main>
  </body>
</html>

A complete list of block elements can be found at developer.mozilla.org/en-US/docs/Web/HTML/Block-level_elements. Likewise a list of inline elements is at developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements.

4.1.28. <video>

The <video> tag does what its name suggests, i.e. it defines video. It supports the following particular attributes:

Name Value Description

autoplay

play video automatically

controls

display video controls

height

pixels

height of the video player

loop

video will loop indefinitely (if supported by browser)

muted

muted video output

poster

URL

image to be shown while video is downloading and playback has not started

preload

auto, metadata, none

how the video should be loaded (cf. www.w3schools.com/tags/att_audio_preload.asp)

src

URL

video URL

width

pixels

width of the video player

Video file formats

There are three video file formats currently supported. They are MP4, WebM and OGG. Here is an overview of browser support:

MP4 WebM OGG

Firefox

yes

yes

yes

Chrome

yes

yes

yes

Internet Explorer

yes

no

no

Safari

yes

no

no

MIME type

video/mp4

video/webm

video/ogg

Within the <video> tag we use the <source> tag to specify multiple video sources that the browser can choose from, based on its file format support.

If we need to convert between the different video file formats we can use a number of free tools, such as Miro Video Converter (www.mirovideoconverter.com) or Handbrake (handbrake.fr).

Here is a simple example of the <video> tag in action:

video1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Video example</title>
    <meta charset=utf-8>
  </head>
  <body>
    <main>
      <video controls autoplay loop
        src=http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4>
        Your browser does not support the video tag.
      </video>
    </main>
  </body>
</html>

Text inside the <video> opening and closing tag will be shown in browsers that do not support the tag.

4.1.29. <audio>

The <audio> tag does what its name suggests, i.e. it defines sound. It supports the following particular attributes:

Name Value Description

autoplay

play audio automatically

controls

display audio controls

loop

audio will loop indefinitely (if supported by browser)

muted

muted audio output

preload

auto, metadata, none

how the audio should be loaded (cf. www.w3schools.com/tags/att_audio_preload.asp)

src

URL

audio URL

Audio file formats

There are three audio file formats currently supported. They are MP3, WAV and OGG. Here is an overview of browser support and main format features:

MP3 OGG WAV

Firefox

yes

yes

yes

Chrome

yes

yes

yes

Internet Explorer

yes

no

no

Safari

yes

yes

no

MIME type

audio/mpeg

audio/ogg

audio/wav

lossless

no

no

usually yes

compressed

yes

yes

usually no

If we need to convert between the different audio file formats we can use a number of free tools, such as Audacity (audacity.sourceforge.net). To produce our own music, we can use the outstanding LMMS (lmms.sourceforge.net) or AudioTool (www.audiotool.com).

Here is a simple example of the <audio> tag in action:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Audio example</title>
    <meta charset=utf-8>
  </head>
  <body>
    <main>
      <audio controls autoplay loop>
        <source src=http://api.audiotool.com/track/ge_trance_1/9/mixdown.ogg
                type=audio/ogg>
        <source src=http://api.audiotool.com/track/ge_trance_1/9/mixdown.mp3
            type=audio/mpeg>
        Your browser does not support the audio tag.
      </audio>
    </main>
  </body>
</html>

Note that the browser will use the first file format that it supports from those listed. The current versions of the main browsers all support MP3. If we only want to support those we can omit the <source> tag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Audio example</title>
    <meta charset=utf-8>
  </head>
  <body>
    <main>
      <audio controls autoplay loop
           src=http://api.audiotool.com/track/ge_trance_1/9/mixdown.mp3>
        Your browser does not support the audio tag.
      </audio>
    </main>
  </body>
</html>

Text inside the <audio> opening and closing tag will be shown in browsers that do not support the tag.

4.1.30. Additional elements

<pre>

The <pre> tag defines preformatted text. Text is displayed in a fixed-width font and preserves both spaces and line breaks (cf. www.w3schools.com/tags/tag_pre.asp).

Example:

pre1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Preformatted Text Example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <pre>
This    is           preformatted text.
Spaces and linebreaks are preserved.
The font used by the browser has fixed width.
    </pre>
  </body>
</html>
<mark>

This element is used to highlight text (cf. www.w3schools.com/tags/tag_mark.asp). Example:

mark1
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Mark example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <p>The <mark>mark element</mark> is used to highlight text in HTML5.</p>
    </main>
  </body>
</html>
<address>

This element is used to display contact information for a person, people or organization. It should include physical and/or digital location/contact information and a means of identifying a person(s) or organization the information pertains to. (cf. www.w3.org/TR/html5/grouping-content.html#elementdef-address).

Example:

address1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Address example</title>
    <meta charset=UTF-8>
  </head>
  <body>
    <footer>
      <address>
        <a href=mailto:gilles.everling@education.lu>Gilles Everling</a>
      </address>
    </footer>
  </body>
</html>
<time>
<ins>
<del>
<iframe>
iframe1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>iframe example</title>
    <meta charset=utf-8>
    <style>
      nav {
        position:         fixed;
        left:             0;
        top:              0;
        bottom:           0;
        width:            100px;
        background-color: lightgoldenrodyellow;
      }

      main {
        position:          absolute;
        left:              100px;
        top:               0;
        bottom:            0;
        right:             0;
        background-color:  lightblue;
        animation:         animate 60s linear 5s infinite;
      }

      iframe {
        display: block;
        width:   100%;
        height:  100%;
        border:  none;
      }

      @keyframes animate {
        to {
          transform: rotateX(360deg) rotateY(360deg);
        }
      }

      ul {
        list-style-type: none;
        padding-left:    10px;
      }

      li {
        padding-top: 5px;
      }
    </style>
  </head>
  <body>
    <nav>
      <ul>
        <li><a href=https://students.btsi.lu/evegi144/WAD/WMOTUInvadersOO
             target=myFrame>WMOTU Invaders</a></li>
        <li><a href=https://students.btsi.lu/evegi144/WAD/WMOTUQuack
             target=myFrame>WMOTU Quack</a></li>
      </ul>
    </nav>
    <main>
      <iframe name=myFrame></iframe>
    </main>
  </body>
</html>
iframe2
1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang=en>
  <head>
    <title></title>
    <meta charset=UTF-8>
  </head>
  <body>
    <main>
      <iframe width=560 height=315 src=https://www.youtube.com/embed/-H2x_tGAxSM?rel=0
          allowfullscreen></iframe>
    </main>
  </body>
</html>

4.1.31. <embed>

This tag creates a container for a plug-in, such as Adobe Reader:

embed1
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Embed example</title>
    <meta charset=utf-8>
  </head>
  <body>
    <main>
      <embed src=T-IF-WEB2-WSERS1_LP.pdf width=1000 height=800>
    </main>
  </body>
</html>

4.1.35. Quiz

Take the w3schools quiz at www.w3schools.com/quiztest/quiztest.asp?qtest=HTML5 as a fun way to check you are as good as you think you are.

4.2. CSS3

CSS is a style sheet language that allows authors and users to attach style (e.g., fonts and spacing) to structured documents (e.g., HTML documents and XML applications). By separating the presentation style of documents from the content of documents, CSS simplifies Web authoring and site maintenance.

The official CSS3 specifications can be found at www.w3.org/Style/CSS/current-work.

What can be done with CSS? Here's an example.

4.2.1. Include CSS3

There are four ways we can style our web page with CSS3.

Inline

We use the style attribute of a specific element to style it.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Inline styling with CSS3</title>
    <meta charset=utf-8>
  </head>
  <body>
    <main style='background-color: gold; color: black'>
      This element is style with inline CSS3.
    </main>
  </body>
</html>
Embedded

We use the <style> tag to embed CSS in the head of our document.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Embedded CSS3</title>
    <meta charset=utf-8>
    <style>
      main {
        background-color: lightcoral;
      }

      p {
        border: 2px dashed green;
        color: lime;
      }
    </style>
  </head>
  <body>
    <main>
      <p>All elements styled by embedded CSS3.</p>
    </main>
  </body>
</html>
External

We use the <link> tag to include an external CSS style sheet in the head of our document.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>External CSS3 style sheet</title>
    <meta charset=utf-8>
    <link href=external1.css rel=stylesheet>
  </head>
  <body>
    <main>
      <p>All elements styled via an external CSS3 style sheet.</p>
    </main>
  </body>
</html>
1
2
3
4
5
6
7
8
main {
  background-color: lightcoral;
}

p {
  border: 2px dashed green;
  color: lime;
}
Imported

We use the @import rule to include an external CSS style sheet in the current style sheet. See developer.mozilla.org/en-US/docs/Web/CSS/@import and www.w3.org/TR/CSS2/cascade.html#at-import.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Imported CSS3 style sheet</title>
    <meta charset=utf-8>
    <style>
      @import url('external1.css');
      aside {
        padding: 10px;
        background-color: mediumorchid;
      }
    </style>
  </head>
  <body>
    <main>
      <p>Styled via an imported CSS3 style sheet.</p>
      <aside>Styled via embedded CSS.</aside>
    </main>
  </body>
</html>
1
2
3
4
5
6
7
8
main {
  background-color: lightcoral;
}

p {
  border: 2px dashed green;
  color: lime;
}
Rules of precedence

A browser processes styles in the order described at www.w3.org/TR/css3-cascade/#cascading-origins. A somewhat simplified illustration of the cascade looks like this:

CSSCascade

However, we can influence rule precedence by either changing the order of inclusion or by using the !important annotation.

If we include an external style sheet after the declaration of the embedded style sheet in the head of our document, the external styles will overwrite the embedded ones.

In the following example, the paragraph background color would normally be green, given that inline styling takes precedence over embedded styling. However, the !important annotation gives the embedded style a higher priority:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Changing the cascade with !important</title>
    <meta charset=utf-8>
    <style>
      p {
        background-color: gold !important;
      }
    </style>
  </head>
  <body>
    <main>
      <p style='background-color: green;'>Some text</p>
    </main>
  </body>
</html>

You can find the default style sheets used by the main browsers at the following links (cf. stackoverflow.com/questions/6867254/browsers-default-css-for-html-elements):

Firefox

mxr.mozilla.org/mozilla-central/source/layout/style/html.css

Internet Explorer

www.iecss.com

Chrome

trac.webkit.org/browser/trunk/Source/WebCore/css/html.css

Opera

www.iecss.com/opera-10.51.css

HTML5 recommendation

www.w3.org/TR/html5/rendering.html

4.2.2. Syntax

CSSSyntax
This site is a CSS3 learner’s paradise: www.w3schools.com/css/css_examples.asp
Comments

You can comment out parts of a line or even several lines by enclosing them between /* and */:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>CSS comment example 1</title>
    <meta charset=utf-8>
    <style>
      body {
        background-color: green;
        /*display: none;
        opacity: 0.5;*/
      }
    </style>
  </head>
  <body>
  </body>
</html>

Comments cannot be nested, i.e. this won’t work:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>CSS comment example 1</title>
    <meta charset=utf-8>
    <style>
      body {
        background-color: green;
        /*display: /*block*/none;
        opacity: 0.5;*/
      }
    </style>
  </head>
  <body>
  </body>
</html>
Variables

Variables are available since Firefox 29 and enabled by default starting in Firefox 31. Here are the details: developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables

4.2.4. Properties

At www.w3schools.com/cssref/default.asp you can find easy to understand explanations as well as examples for pretty much every CSS property. This is an extremely useful resource that you should use.

www.w3.org/TR/css-2010/#properties and meiert.com/en/indices/css-properties provide an almost complete list of CSS properties with links to the specifications and in-depth explanations, which are useful for WMOTUs.

object-fit

Used to specify how an <img> or <video> should be resized to fit its container. See www.w3schools.com/css/css3_object-fit.asp. Also take a look at object-position.

overflow
background

Scaling an image to its maximum displayable size without distorting the proportions can be done like this:

backgroundmaxsize1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Maximum size background image scaling without distortion</title>
    <meta charset=utf-8>
    <style>
      main {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-image: url(DSC00538.JPG);
        background-repeat: no-repeat;
        background-size: contain;
      }
    </style>
  </head>
  <body>
    <main>
    </main>
  </body>
</html>
content

A great list of Unicode symbols can be found at inamidst.com/stuff/unidata.

content1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Content demo</title>
    <meta charset=UTF-8>
    <style>
      button::before {
        content: '\2709';
      }
    </style>
  </head>
  <body>
    <button> Email us</button>
  </body>
</html>
word-wrap

word-wrap allows us to solve some space constraint problems, as shown in this example:

word wrap1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Word wrap example 1</title>
    <meta charset=utf-8>
    <style>
      section {
        width: 50px;
        background-color: blueviolet;
      }

      #section2 {
        word-wrap: break-word;
      }
    </style>
  </head>
  <body>
    <main>
      <section>
        <h1>Section 1</h1>
        dassssssssssssssssssssssssssssssssssssssssss
      </section>
      <hr>
      <section id=section2>
        <h1>Section 2</h1>
        dassssssssssssssssssssssssssssssssssssssssss
      </section>
    </main>
  </body>
</html>
word-break

In a table you might have to use word-break instead of word-wrap and set it to break-word or break-all. You also must set the width or max-width of the cell for this to work.

contenteditable
The contenteditable attribute specifies whether the content of an element is editable or not.
resize

The resize (www.cssportal.com/css-properties/resize.php and developer.mozilla.org/en-US/docs/Web/CSS/resize) property allows us to make an element resizable. Note that in order for the resizing to work, you need to set the overflow property to something different from the standard visible.

4.2.5. Selectors

Study the excellent table at www.w3schools.com/cssref/css_selectors.asp to learn the power and expressiveness of CSS selectors.

Here is a simple example:

hover1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Hover demo</title>
    <meta charset=utf-8>
    <style>
      p {
        display: none;
      }

      main {
        width: 500px;
        height: 500px;
        background-color: black;
      }
      main:hover > p {
        background-color: red;
        display: inline-block;
      }
    </style>
  </head>
  <body>
    <main>
      <p>Paragraph</p>
    </main>
  </body>
</html>

4.2.6. Box model

boxmodel1
boxmodel2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>CSS3 box model illustration</title>
    <meta charset=utf-8>
    <style>
      body {
        background-color: black;
      }

      header {
        background-color: green;
        border: 20px groove red;
        text-align: center;
      }

      h1 {
        background-color: gold;
        margin: 50px;
        padding: 30px;
        border: 10px dotted steelblue;
      }

      section {
        background-color: khaki;
        text-align: center;
        margin: 20px;
        padding: 40px;
        border: 10px double blue;
      }
    </style>
  </head>
  <body>
    <header>
      This is the header.
      <h1>This is the heading (h1).</h1>
    </header>
    <main>
      <section>
        This is a section.
      </section>
    </main>
  </body>
</html>
By default, i.e. if you have not changed box-sizing, the width and height properties in CSS3 do NOT include the padding, border and margin! Thus, if an element has content width of 200px, padding of 5px, a border width of 2px and a margin of 10px, the real width of the element will be 200 + 2 * 5 + 2 * 2 + 2 * 10 = 234px.

4.2.7. Layout

Normal flow

A browser renders our HTML code line by line in the order it appears in our HTML document. This is called normal flow. The following is a simple example, illustrating normal flow and the nesting of elements:

normalflow1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Normal flow example 1</title>
    <meta charset=utf-8>
    <style>
      section {
        width: 400px;
        height: 250px;
        border: 2px dashed green;
        margin: 5px;
        padding: 5px;
      }

      article {
        width: 300px;
        height: 150px;
        border: 1px inset blue;
        margin: 3px;
        padding: 3px;
      }

      p, aside {
        background-color: lightgoldenrodyellow;
        border: 1px groove gold;
        margin: 3px;
        padding: 3px;
      }
    </style>
  </head>
  <body>
    <main>
      <section>
        Section 1 does not contain any elements.
      </section>
      <section>
        Section 2 contains 3 nested elements:
        <article>
          This is an article
          <p>This is a paragraph nested inside an article nested inside a
            section nested inside the main element nested inside the body.</p>
        </article>
        <aside>This is an aside nested inside section 2 ...</aside>
      </section>
    </main>
  </body>
</html>

Now let’s try to build the following layout:

float
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Normal flow example 2</title>
    <meta charset=utf-8>
    <style>
      nav {
        border: 2px dotted blueviolet;
        width: 10%;
        height: 80px;
        margin: 5px;
        padding: 5px;
      }

      section {
        width: 40%;
        border: 2px solid #90ff65;
        margin: 5px;
        padding: 5px;
      }

      header {
        border: 2px ridge black;
        text-align: center;
      }

      footer {
        border: 2px outset hotpink;
        text-align: center;
      }
    </style>
  </head>
  <body>
    <header>Header</header>
    <nav>Navigation</nav>
    <main>
      <section>Section 1</section>
      <section>Section 2</section>
    </main>
    <footer>Footer</footer>
  </body>
</html>

Unfortunately, this is not exactly what we want.

Floats

To solve our layout problem from the previous subsection, we need to take the navigation and two section elements out of the normal flow. We can do this using the float and clear properties:

float1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Float example 1</title>
    <meta charset=utf-8>
    <style>
      nav {
        float:   left;
        border:  2px dotted blueviolet;
        width:   10%;
        height:  80px;
        margin:  5px;
        padding: 5px;
      }

      section {
        float:   left;
        width:   40%;
        border:  2px solid #90ff65;
        margin:  5px;
        padding: 5px;
      }

      header {
        border:     2px ridge black;
        text-align: center;
      }

      footer {
        clear:      left;
        border:     2px outset hotpink;
        text-align: center;
      }
    </style>
  </head>
  <body>
    <header>Header</header>
    <nav>Navigation</nav>
    <main>
      <section>Section 1</section>
      <section>Section 2</section>
    </main>
    <footer>Footer</footer>
  </body>
</html>

It is important to understand that float takes the floated element out of the normal flow and allows to float it on the left or right side of its container. Only block elements can be floated. To return to the normal flow, we use the clear property. We can clear only the left, only the right or both sides.

Remove the clear property from the footer rule and see what happens.

Instead of using clear we can use the overflow property on the containing element:

float2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Float example 2</title>
    <meta charset=utf-8>
    <style>
      nav {
        float:   left;
        border:  2px dotted blueviolet;
        width:   10%;
        height:  80px;
        margin:  5px;
        padding: 5px;
      }

      section {
        float:   left;
        width:   40%;
        border:  2px solid #90ff65;
        margin:  5px;
        padding: 5px;
      }

      header {
        border:     2px ridge black;
        text-align: center;
      }

      footer {
        border:     2px outset hotpink;
        text-align: center;
      }

      main {
        overflow: auto;
      }

      article {
        background-color: chartreuse;
      }
    </style>
  </head>
  <body>
    <header>Header</header>
    <nav>Navigation</nav>
    <main>
      <section>Section 1</section>
      <section>Section 2
        <header>Header</header>
        <article>Article 1</article>
        <article>Article 2</article>
        <footer>Footer</footer>
      </section>
    </main>
    <footer>Footer</footer>
  </body>
</html>

Floats can be very helpful in solving some simple layout problems, like in this vertical alignment example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Float example 3</title>
    <meta charset=utf-8>
    <style>
      #a1 {
        float: left;
      }

      span {
        display: inline-block;
      }
    </style>
  </head>
  <body>
    <main> <!-- How do we get link1 to be aligned at the top instead of at the bottom?-->
      <a>link1</a><span>a<br>b</span>
      <br>
      <a id=a1>link1</a><span>a<br>b</span>
    </main>
  </body>
</html>
Positioning

The position property allows us to take an element out of the normal flow and position it exactly as we like (cf. developer.mozilla.org/en-US/docs/Web/CSS/position).

It is important to note that an element with position absolute is positioned relative to the nearest positioned ancestor (instead of positioned relative to the viewport, like fixed). However; if an absolute positioned element has no positioned ancestors, it uses the document body, and moves along with page scrolling. Note: A "positioned" element is one whose position is anything except static.

Let’s have a look at some examples:

Positioning1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Positioning example 1</title>
    <meta charset=UTF-8>
    <style>
      body {
        margin: 0;
      }

      header {
        background-color: gold;
        text-align:       center;
      }

      nav {
        background-color: navajowhite;
      }

      section {
        background-color: lightgrey;
      }

      footer {
        background-color: aqua;
        text-align:       center;
      }

      #article1 {
        background-color: yellow;
        opacity:          0.3;
      }

      #article2 {
        background-color: indianred;
        opacity:          0.3;
      }

      #article3 {
        background-color: yellowgreen;
      }

      #article4 {
        background-color: white;
      }

      aside {
        background-color: red;
      }

      h1 {
        margin: 0;
      }

      ul {
        padding: 0;
      }
    </style>
  </head>
  <body>
    <header>
      <h1>LAM T0IF WMOTU</h1>
    </header>
    <nav>
      <ul>
        <li><a href=#>Link 1</a></li>
        <li><a href=#>Link 2</a></li>
        <li><a href=#>Link 3</a></li>
        <li><a href=#>Link 4</a></li>
      </ul>
    </nav>
    <main>
      <section>
        <article id=article1></article>
        <aside>I'm so sticky</aside>
        <article id=article2></article>
        <article id=article3></article>
        <article id=article4></article>
      </section>
    </main>
    <footer>&copy; 2018 LAM T0IF</footer>
  </body>
</html>
Positioning2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Positioning example 2</title>
    <meta charset=UTF-8>
    <style>
      body {
        margin:   0;
        overflow: hidden;
      }

      main {
        overflow: auto;
        position: absolute;
        left:     100px;
        top:      40px;
        right:    0;
        bottom:   20px;
      }

      header {
        background-color: gold;
        text-align:       center;
        position:         fixed;
        top:              0;
        left:             0;
        width:            100%;
        height:           40px;
      }

      nav {
        background-color: navajowhite;
        position:         fixed;
        top:              40px;
        left:             0;
        width:            100px;
        bottom:           20px;
      }

      section {
        background-color: lightgrey;
      }

      footer {
        background-color: aqua;
        text-align:       center;
        position:         fixed;
        bottom:           0;
        left:             0;
        height:           20px;
        width:            100%;
      }

      #article1 {
        background-color: yellow;
        position:         relative;
        left:             50px;
        top:              100px;
      }

      #article2 {
        background-color: indianred;
        position:         absolute;
        left:             20px;
        top:              420px;
      }

      #article3 {
        background-color: yellowgreen;
        position:         fixed;
        left:             50px;
        top:              300px;
      }

      #article4 {
        background-color: white;
      }

      aside {
        position:         sticky;
        top:              0;
        background-color: red;
      }

      h1 {
        margin: 0;
      }

      ul {
        padding: 0;
      }
    </style>
  </head>
  <body>
    <header>
      <h1>LAM T0IF WMOTU</h1>
    </header>
    <nav>
      <ul>
        <li><a href=#>Link 1</a></li>
        <li><a href=#>Link 2</a></li>
        <li><a href=#>Link 3</a></li>
        <li><a href=#>Link 4</a></li>
      </ul>
    </nav>
    <main>
      <section>
        <article id=article1></article>
        <aside>I'm so sticky</aside>
        <article id=article2></article>
        <article id=article3></article>
        <article id=article4></article>
      </section>
    </main>
    <footer>&copy; 2018 LAM T0IF</footer>
  </body>
</html>

On scroll-linked effects:

developer.mozilla.org/en-US/docs/Mozilla/Performance/Scroll-linked_effects

staktrace.com/spout/entry.php?id=834

Table layout
Scrollable HTML5 table with fixed header

This is a classic problem that has not had many fully satisfying solutions so far. Some interesting discussions on the topic can be found here:

stackoverflow.com/questions/673153/html-table-with-fixed-headers/25902860

stackoverflow.com/questions/673153/html-table-with-fixed-headers/25818428

stackoverflow.com/questions/17584702/how-to-add-a-scrollbar-to-an-html5-table

stackoverflow.com/questions/8423768/freeze-the-top-row-for-an-html-table-only-fixed-table-header-scrolling

www.sitepoint.com/community/t/flexible-html-table-with-fixed-header-and-footer-around-a-scrollable-body/271162/31

stackoverflow.com/questions/19559197/how-to-make-scrollable-table-with-fixed-headers-using-css

salzerdesign.com/test/fixedTable.html

blog.freestylecoding.com/archive/2011/04/19/html-table-with-fixed-header-and-scrollable-body.aspx

The following table lists some solutions I’ve found and gives a brief comment:

students.btsi.lu/evegi144/WAD/CSS3/table1.html

Does not work if the window is too small and a horizontal scroll bar appears.

students.btsi.lu/evegi144/WAD/CSS3/table2.html

Same issue.

students.btsi.lu/evegi144/WAD/CSS3/table3.html

Same issue.

students.btsi.lu/evegi144/WAD/CSS3/table4.html

Needs setting column width.

students.btsi.lu/evegi144/WAD/CSS3/table5.html

Simple but does not work.

students.btsi.lu/evegi144/WAD/CSS3/table6.html

Works very well but requires a huge amount of CSS and divs.

students.btsi.lu/evegi144/WAD/CSS3/table7.html

Very simple solution that works but not very smoothly on mobiles as for the reasons explained above under scroll-linked effects. Until position:sticky works correctly in the main browsers this will be my first choice.

students.btsi.lu/evegi144/WAD/CSS3/table8.html

This is the ideal solution.

doctorDestructo’s fiddles are worth having a look.

CSS tables

CSS allows us to style elements as tables, which opens up a very powerful layout mechanism. See www.w3.org/TR/CSS21/visuren.html#propdef-display and www.w3.org/TR/CSS21/tables.html for the details.

Example:

TableLayout1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Table layout example 1</title>
    <meta charset=UTF-8>
    <style>
      main {
        display: table;
      }

      section {
        display: table-row;
      }

      article {
        display: table-cell;
      }
    </style>
  </head>
  <body>
    <main>
      <section>
        <article></article>
        <article></article>
      </section>
      <section>
        <article>afadsfadsfdas</article>
        <article>afadsfadsadasdsadasddsfdas</article>
      </section>
      <section>
        <article>sadsa</article>
        <article>sadsadsasadsadsa</article>
      </section>
    </main>
  </body>
</html>
Vertical centering

www.w3.org/Style/Examples/007/center

www.vanseodesign.com/css/vertical-centering

Flexbox, as described in a later section, is by far the easiest way to center any element.

Example:

VerticalCentering1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Centering example</title>
    <meta charset=UTF-8>
    <style>
      main {
        position:         absolute;
        top:              0;
        left:             0;
        height:           100%;
        width:            100%;
        background-color: lightblue;
        display:          flex;
      }

      img {
        margin: auto;
      }
    </style>
  </head>
  <body>
    <main>
      <img src=logo_ltam.gif alt="LTAM Logo">
    </main>
  </body>
</html>

Here a more generic way to center any element without styling it: students.btsi.lu/evegi144/WAD/CSS3/centering2.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Centering example</title>
    <meta charset=UTF-8>
    <style>
      main {
        position:         absolute;
        top:              0;
        left:             0;
        height:           100%;
        width:            100%;
        background-color: lightblue;
        display:          flex;
        align-items:      center;
        justify-content:  center;
        /*text-align:       center;*/
        flex-flow:        column;
      }
    </style>
  </head>
  <body>
    <main>
      <section>
        <img src=logo_ltam.gif alt="LTAM Logo">
      </section>
      <section>Section 2</section>
    </main>
  </body>
</html>
Flexible box layout

According to www.w3.org/TR/css3-flexbox, flexible box layout is

a CSS box model optimized for user interface design. In the flex layout model, the children of a flex container can be laid out in any direction, and can “flex” their sizes, either growing to fill unused space or shrinking to avoid overflowing the parent. Both horizontal and vertical alignment of the children can be easily manipulated. Nesting of these boxes (horizontal inside vertical, or vertical inside horizontal) can be used to build layouts in two dimensions.

It is a big step forward in terms of GUI development and will be our preferred approach.

To learn Flexbox in a fun way, take a look at www.flexboxdefense.com and flexboxfroggy.com.

You can find in-depth information and examples at the following links:

developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout

www.w3schools.com/cssref/css3_pr_flex.asp

bocoup.com/weblog/dive-into-flexbox

www.w3.org/TR/css3-flexbox

css-tricks.com/snippets/css/a-guide-to-flexbox

html5please.com/\#flexbox

philipwalton.github.io/solved-by-flexbox

www.sketchingwithcss.com/samplechapter

www.sketchingwithcss.com/samplechapter/cheatsheet.html

www.smashingmagazine.com/2013/05/22/centering-elements-with-flexbox

designshack.net/articles/css/build-a-web-page-with-css3-flexbox

www.html5rocks.com/en/tutorials/flexbox/quick

Let’s start with a simple header - main - footer layout, where the main part contains a navigation, a section and an aside. Note that the order of the navigation and aside are changed using CSS.

Study the comments in the CSS file together with the links above to gain a deeper understanding of flex layout.

FlexTest1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Flexible Box Layout Test 1</title>
    <meta charset=utf-8>
    <meta name=viewport content="width=device-width, initial-scale=1">
    <style>
      /* This will make sure that our GUI fills the whole browser window. */
      html, body {
        width:  100%;
        height: 100%;
        margin: 0;
      }

      body {
        background: #999999;
        display:    flex; /* This element is a flex container. */
        flex-flow:  column; /* Change the main axis to column instead of row. */
        overflow:   hidden; /* We don't want scrollbars. */
      }

      main {
        margin:   0;
        padding:  0;
        display:  flex; /* This is another flex container. */
        /* It will grow 3 times faster and shrink at the same speed as the others. */
        flex:     auto;
        overflow: hidden; /* We don't want scrollbars. */
      }

      main > section {
        margin:        4px;
        padding:       5px;
        border:        1px solid #cccc33;
        border-radius: 7pt;
        background:    #dddd88;
        flex:          3 1 60%;
        order:         2; /* This element will be displayed in second position. */
        overflow:      auto; /* We want scrollbars when required by the content. */
      }

      main > nav {
        margin:        4px;
        padding:       5px;
        border:        1px solid #8888bb;
        border-radius: 7pt;
        background:    #ccccff;
        flex:          1 6 20%;
        order:         3; /* This element will be displayed in third position. */
      }

      main > aside {
        margin:        4px;
        padding:       5px;
        border:        1px solid #8888bb;
        border-radius: 7pt;
        background:    #ccccff;
        flex:          1 6 20%;
        order:         1; /* This element will be displayed in first position. */
      }

      header, footer {
        margin:        4px;
        padding:       5px;
        border:        1px solid #eebb55;
        border-radius: 7pt;
        background:    #ffeebb;
        height:        50px;
      }

      /* Too narrow to support three columns */
      @media all and (max-width: 640px) {
        main {
          flex-flow: column;
        }

        main > section, main > nav, main > aside {
          /* Return them to document order */
          order: 0;
        }

        main > nav, main > aside, header, footer {
          min-height: 50px;
          max-height: 50px;
        }
      }

    </style>
  </head>
  <body>
    <header>header</header>
    <main>
      <nav>nav</nav>
      <section>section</section>
      <aside>aside</aside>
    </main>
    <footer>footer</footer>
  </body>
</html>

Now we let the user resize some of the elements:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Flexible Box Layout Test 2</title>
    <meta charset=utf-8>
    <meta name=viewport content="width=device-width, initial-scale=1">
    <style>
      body {
        position:   absolute;
        top:        0;
        left:       0;
        width:      100%;
        height:     100%;
        background: #999999;
        display:    flex;
        flex-flow:  column;
        margin:     0;
        overflow:   hidden;
      }

      main {
        min-height: 50px;
        margin:     0;
        padding:    0;
        display:    flex;
        flex:       auto;
      }

      main > article {
        margin:        4px;
        padding:       5px;
        border:        1px solid #cccc33;
        border-radius: 7pt;
        background:    #dddd88;
        flex:          auto;
        min-width:     50px;
      }

      main > nav {
        margin:        4px;
        padding:       5px;
        border:        1px solid #8888bb;
        border-radius: 7pt;
        background:    #ccccff;
        min-width:     150px;
      }

      main > aside {
        margin:        4px;
        padding:       5px;
        border:        1px solid #8888bb;
        border-radius: 7pt;
        background:    #ccccff;
        min-width:     50px;
        flex:          auto;
      }

      header, footer {
        display:       block;
        margin:        4px;
        padding:       5px;
        min-height:    100px;
        border:        1px solid #eebb55;
        border-radius: 7pt;
        background:    #ffeebb;
      }

      .splitter {
        border-left: 2px solid grey;
        width:       2px;
        min-width:   2px;
        cursor:      col-resize;
      }

      /* Too narrow to support three columns */
      @media all and (max-width: 640px) {
        main {
          flex-flow:      column;
        }

        main > nav, main > aside, header, footer {
          min-height: 50px;
          max-height: 50px;
        }
      }

    </style>
    <script src=flextest2.js></script>
  </head>
  <body>
    <header>header</header>
    <main>
      <nav>nav</nav>
      <article>article</article>
      <div class="splitter"></div>
      <aside>aside</aside>
    </main>
    <footer>footer</footer>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
'use strict';

let lastFirstElWidth = 0, lastThirdElWidth = 0;

// https://hacks.mozilla.org/2013/12/application-layout-with-css3-flexible-box-module
class Splitter {
  constructor(handler, leftEl, rightEl) {
    this.lastX = 0;
    this.dragListener = null;
    this.endDragListener = null;
    this.leftEl = leftEl;
    this.rightEl = rightEl;

    handler.addEventListener('mousedown', evt => {
      evt.preventDefault();
      this.lastX = evt.clientX;
      // http://msdn.microsoft.com/en-us/library/windows/apps/hh703713.aspx
      this.dragListener = this.drag;
      this.endDragListener = this.endDrag;
      addEventListener('mousemove', this.dragListener);
      addEventListener('mouseup', this.endDragListener);
    });

    this.drag = evt => {
      let wL, wR;
      const wDiff = evt.clientX - this.lastX;
      wL = getComputedStyle(this.leftEl).width;
      wR = getComputedStyle(this.rightEl).width;
      wL = parseInt(wL) + wDiff;
      wR = parseInt(wR) - wDiff;
      this.leftEl.style.width = wL + 'px';
      this.rightEl.style.width = wR + 'px';
      this.lastX = evt.clientX;
      lastFirstElWidth = wL;
      lastThirdElWidth = wR;
    };

    this.endDrag = () => {
      removeEventListener('mousemove', this.dragListener);
      removeEventListener('mouseup', this.endDragListener);
    };
  };
}

const init = () => {
  const splitter = new Splitter(document.getElementsByClassName('splitter')[0],
    document.getElementsByTagName('article')[0],
    document.getElementsByTagName('aside')[0]);

  /* Our CSS switches flex flow to column if window width <= 640.
   In this case we need to remove the width set by the splitter dragging,
   otherwise the layout won't be right aligned on small screens.
   If window width increases again, we want the previous widths back.
   */
  const handleResize = () => {
    if (innerWidth <= 640) {
      document.querySelector('article').style.width = '';
      document.querySelector('aside').style.width = '';
    }
    else {
      document.querySelector('article').style.width = lastFirstElWidth + 'px';
      document.querySelector('aside').style.width = lastThirdElWidth + 'px';
    }
  };

  window.addEventListener('resize', handleResize);
};

window.addEventListener('load', init);

Some more resizability:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Flexible Box Layout Test 3</title>
    <meta charset=utf-8>
    <meta name=viewport content="width=device-width, initial-scale=1">
    <style>
      body {
        position:   absolute;
        top:        0;
        left:       0;
        width:      100%;
        height:     100%;
        background: #999999;
        display:    flex;
        flex-flow:  column;
        margin:     0;
        overflow:   hidden;
      }

      main {
        min-height: 50px;
        margin:     0;
        padding:    0;
        display:    flex;
        flex:       auto;
      }

      main > article {
        margin:        4px;
        padding:       5px;
        border:        1px solid #cccc33;
        border-radius: 7pt;
        background:    #dddd88;
        flex:          auto;
        min-width:     50px;
      }

      main > nav {
        margin:        4px;
        padding:       5px;
        border:        1px solid #8888bb;
        border-radius: 7pt;
        background:    #ccccff;
        min-width:     50px;
      }

      main > aside {
        margin:        4px;
        padding:       5px;
        border:        1px solid #8888bb;
        border-radius: 7pt;
        background:    #ccccff;
        flex:          auto;
        min-width:     50px;
      }

      header, footer {
        margin:        4px;
        padding:       5px;
        min-height:    50px;
        border:        1px solid #eebb55;
        border-radius: 7pt;
        background:    #ffeebb;
      }

      .verticalSplitter {
        border-left: 2px solid grey;
        width:       2px;
        min-width:   2px;
        cursor:      col-resize;
      }

      .horizontalSplitter {
        border-top: 2px solid grey;
        height:     2px;
        min-height: 2px;
        cursor:     row-resize;
      }

      /* Too narrow to support three columns */
      @media all and (max-width: 640px) {
        main {
          flex-flow: column;
        }

        main > nav, header, footer {
          height: 50px;
        }

        .horizontalSplitter, .verticalSplitter {
          display: none;
        }
      }

    </style>
  </head>
  <body>
    <header>header</header>
    <div id=hs1 class=horizontalSplitter></div>
    <main>
      <nav>nav</nav>
      <article>article</article>
      <div class=verticalSplitter></div>
      <aside>aside</aside>
    </main>
    <div id=hs2 class=horizontalSplitter></div>
    <footer>footer</footer>
    <script src=flextest3.js></script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
'use strict';

let lastFirstElWidth = 0, lastThirdElWidth = 0;

// https://hacks.mozilla.org/2013/12/application-layout-with-css3-flexible-box-module
class Splitter {
  constructor(vertical) {
    this.vertical = vertical;
    this.lastCoord = 0;

    this.init = (splitter, firstEl, thirdEl) =>
    {
      this.firstEl = firstEl;
      this.thirdEl = thirdEl;
      splitter.addEventListener('mousedown', evt => {
        evt.preventDefault();
        if (vertical) this.lastCoord = evt.clientX;
        else this.lastCoord = evt.clientY;
        this.dragListener = this.drag;
        this.endDragListener = this.endDrag;
        addEventListener('mousemove', this.dragListener);
        addEventListener('mouseup', this.endDragListener);
      });
    };

    this.drag = evt => {
      let coord1, coord3, coordDiff;
      if (vertical) {
        coordDiff = evt.clientX - this.lastCoord;
        coord1 = getComputedStyle(this.firstEl).width;
        coord3 = getComputedStyle(this.thirdEl).width;
      }
      else {
        coordDiff = evt.clientY - this.lastCoord;
        coord1 = getComputedStyle(this.firstEl).height;
        coord3 = getComputedStyle(this.thirdEl).height;
      }
      coord1 = parseInt(coord1) + coordDiff;
      coord3 = parseInt(coord3) - coordDiff;
      if (vertical) {
        this.firstEl.style.width = coord1 + 'px';
        this.thirdEl.style.width = coord3 + 'px';
        this.lastCoord = evt.clientX;
        lastFirstElWidth = coord1;
        lastThirdElWidth = coord3;
        console.log(lastFirstElWidth + ' ' + lastThirdElWidth);
      }
      else {
        this.firstEl.style.height = coord1 + 'px';
        this.thirdEl.style.height = coord3 + 'px';
        this.lastCoord = evt.clientY;
      }
    };

    this.endDrag = () => {
      removeEventListener('mousemove', this.dragListener);
      removeEventListener('mouseup', this.endDragListener);
    };
  }
}

const init = () => {
  const verticalSplitter = new Splitter(true);
  verticalSplitter.init(document.getElementsByClassName('verticalSplitter')[0],
    document.querySelector('article'), document.querySelector('aside'));
  const horizontalSplitter1 = new Splitter(false);
  horizontalSplitter1.init(document.getElementById('hs1'),
    document.querySelector('header'), document.querySelector('main'));
  const horizontalSplitter2 = new Splitter(false);
  horizontalSplitter2.init(document.getElementById('hs2'),
    document.querySelector('main'), document.querySelector('footer'));

  /* Our CSS switches flex flow to column if window width <= 640.
     In this case we need to remove the width set by the splitter dragging,
      otherwise the layout won't be right aligned on small screens.
     If window width increases again, we want the previous widths back.
   */
  const handleResize = () => {
    if (innerWidth <= 640) {
      document.querySelector('article').style.width = '';
      document.querySelector('aside').style.width = '';
    }
    else {
      document.querySelector('article').style.width = lastFirstElWidth + 'px';
      document.querySelector('aside').style.width = lastThirdElWidth + 'px';
    }
  };

  window.addEventListener('resize', handleResize);
};

window.addEventListener('load', init);

The following example illustrates how to achieve specific scrollbar behavior:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<!DOCTYPE html>
<html>
  <head>
    <title>Flexible Box Layout Test 4</title>
    <meta charset=utf-8>
    <meta name=viewport content="width=device-width, initial-scale=1">
    <style type="text/css">
      html, body {
        height:  100%;
        width:   100%;
        padding: 0;
        margin:  0;
      }

      body {
        overflow:       hidden;
        display:        flex;
        flex-direction: column;
      }

      header {
        height:     75px;
        min-height: 75px;
      }

      footer {
        height:     25px;
        min-height: 25px;
      }

      main {
        display:      flex;
        flex:         auto;
        border:       solid grey;
        border-width: 1px 0;
        overflow:     hidden;
      }

      nav {
        width:     150px;
        min-width: 150px;
      }

      section {
        border:       solid grey;
        border-width: 0 0 0 1px;
        flex:         auto;
        overflow:     auto;
      }
    </style>
  </head>
  <body>
    <header>header</header>
    <main>
      <nav>nav</nav>
      <section>article<br>read <a
        href="https://hacks.mozilla.org/2013/12/application-layout-with-css3-flexible-box-module/"
        target="_blank">Application Layout with CSS3 Flexible Box Module</a>
        <p style="width:1000px;">
          <?php require_once 'flextest4.txt'; ?>
        </p>
      </section>
    </main>
    <footer>footer</footer>
  </body>
</html>

Finally a more advanced example combining flexbox, splitters and scrollbars:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Flexible Box Layout Test 5</title>
    <meta charset=utf-8>
    <meta name=viewport content="width=device-width, initial-scale=1">
    <style>
      html, body {
        width:  100%;
        height: 100%;
      }

      body {
        background: #999999;
        display:    flex;
        flex-direction:  column;
        margin:     0;
        overflow:   hidden;
      }

      main {
        margin:  0;
        padding: 0;
        display: flex;
        flex:    auto;
        overflow: auto;
      }

      main > nav {
        margin:        4px;
        padding:       5px;
        border:        1px solid #8888bb;
        border-radius: 7pt;
        background:    #ccccff;
        min-width:     50px;
        flex:          auto;
      }

      main > section {
        margin:         4px;
        padding:        5px;
        border:         1px solid #8888bb;
        border-radius:  7pt;
        background:     #ccccff;
        display:        flex;
        flex-direction: column;
        min-width:      50px;
        overflow:       hidden;
      }

      main > section > section {
        display:   flex;
        flex-flow: column;
        flex:      auto;
        overflow:  hidden;
      }

      header, footer {
        margin:        4px;
        padding:       5px;
        min-height:    50px;
        border:        1px solid #eebb55;
        border-radius: 7pt;
        background:    #ffeebb;
      }

      #s1 {
        flex:     auto;
        flex-flow: column;
        overflow: hidden;
      }

      #s1 > article, #s2 {
        overflow: auto;
      }

      .verticalSplitter {
        border-left: 2px solid grey;
        width:       2px;
        min-width:   2px;
        cursor:      col-resize;
      }

      .horizontalSplitter {
        border-top: 2px solid grey;
        height:     2px;
        min-height: 2px;
        cursor:     row-resize;
      }

      /* Too narrow to support three columns */
      @media all and (max-width: 640px) {
        main {
          flex-flow: column;
        }

        .horizontalSplitter, .verticalSplitter {
          display: none;
        }
      }
    </style>
    <script src=flextest5.js></script>
  </head>
  <body>
    <header>header</header>
    <main>
      <nav>nav</nav>
      <div class=verticalSplitter></div>
      <section>
        <section id=s1>
          <header>Header s1</header>
          <article><?php require 'flextest4.txt'; ?></article>
        </section>
        <div id=hs1 class=horizontalSplitter></div>
        <section id=s2><?php require 'flextest4.txt'; ?></section>
      </section>
    </main>
    <footer>footer</footer>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
'use strict';

let verticalSplitter, horizontalSplitter;

// https://hacks.mozilla.org/2013/12/application-layout-with-css3-flexible-box-module
class Splitter {
  constructor(vertical) {
    this.vertical = vertical;
    this.lastCoord = 0;
    if (vertical) {
      this.lastFirstElWidth = 0;
      this.lastThirdElWidth = 0;
    }

    this.init = (splitter, firstEl, thirdEl) =>
    {
      this.firstEl = firstEl;
      this.thirdEl = thirdEl;
      splitter.addEventListener('mousedown', evt => {
        evt.preventDefault();
        if (vertical) this.lastCoord = evt.clientX;
        else this.lastCoord = evt.clientY;
        this.dragListener = this.drag;
        this.endDragListener = this.endDrag;
        addEventListener('mousemove', this.dragListener);
        addEventListener('mouseup', this.endDragListener);
      });
    };

    this.drag = evt => {
      let coord1, coord3, coordDiff;
      if (vertical) {
        coordDiff = evt.clientX - this.lastCoord;
        coord1 = getComputedStyle(this.firstEl).width;
        coord3 = getComputedStyle(this.thirdEl).width;
      }
      else {
        coordDiff = evt.clientY - this.lastCoord;
        coord1 = getComputedStyle(this.firstEl).height;
        coord3 = getComputedStyle(this.thirdEl).height;
      }
      coord1 = parseInt(coord1) + coordDiff;
      coord3 = parseInt(coord3) - coordDiff;
      if (vertical) {
        this.firstEl.style.width = coord1 + 'px';
        this.thirdEl.style.width = coord3 + 'px';
        this.lastCoord = evt.clientX;
        this.lastFirstElWidth = coord1;
        this.lastThirdElWidth = coord3;
      }
      else {
        this.firstEl.style.height = coord1 + 'px';
        this.thirdEl.style.height = coord3 + 'px';
        this.lastCoord = evt.clientY;
      }
    };

    this.endDrag = () => {
      removeEventListener('mousemove', this.dragListener);
      removeEventListener('mouseup', this.endDragListener);
    };
  }
}

const init = () => {
  const verticalSplitter = new Splitter(true);
  const horizontalSplitter = new Splitter(false);
  verticalSplitter.init(document.getElementsByClassName('verticalSplitter')[0],
    document.querySelector('nav'), document.querySelector('section'));
  horizontalSplitter.init(document.getElementById('hs1'),
    document.getElementById('s1'), document.getElementById('s2'));

  /* Our CSS switches flex flow to column if window width <= 640.
     In this case we need to remove the width set by the splitter dragging,
      otherwise the layout won't be right aligned on small screens.
     If window width increases again, we want the previous widths back.
   */
  const handleResize = () => {
    if (innerWidth <= 640) {
      document.querySelector('article').style.width = '';
      document.querySelector('aside').style.width = '';
    }
    else {
      document.querySelector('article').style.width = lastFirstElWidth + 'px';
      document.querySelector('aside').style.width = lastThirdElWidth + 'px';
    }
  };

  window.addEventListener('resize', handleResize);
};

window.addEventListener('load', init);

A flexible navigation menu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<!DOCTYPE html>
<html lang=en>
  <head>
    <meta charset=UTF-8>
    <title>Flexible Box Layout Test 6</title>
    <style>
      html { /* http://www.paulirish.com/2012/box-sizing-border-box-ftw */
        box-sizing: border-box;
      }
      *, *:before, *:after {
        box-sizing: inherit;
      }

      html, body {
        width:  100%;
        height: 100%;
        margin: 0;
      }

      body {
        display:   flex;
        flex-flow: column;
        overflow:  hidden;
      }

      main {
        margin:   0;
        overflow: auto;
      }

      nav {
        padding: 0;
      }

      ul {
        list-style:       none;
        padding:          0;
        display:          flex;
        flex:             auto;
        background-color: pink;
        margin:           0;
      }

      li {
        flex: auto;
      }

      nav > ul > li > a {
        text-decoration:  none;
        margin:           0;
        padding:          0;
        display:          inline-block;
        width:            100%;
        text-align:       center;
        background-color: orange;
        border:           solid black 1px;
      }

      nav > ul > li > a:hover {
        background-color: yellow;
      }

      main > section > a {
        text-decoration: none;
        background-color: tomato;
        border-radius: 5px;
        padding: 5px;
      }
    </style>
  </head>
  <body>
    <nav>
      <ul>
        <li><a href=#about>About</a></li>
        <li><a href=#portfolio>Portfolio</a></li>
        <li><a href=#contact>Contact</a></li>
      </ul>
    </nav>
    <main>
      <section id=about>
        <h1>About</h1>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
      </section>
      <section id=portfolio>
        <h1>Portfolio</h1>
        <?php require_once 'flextest4.txt'; ?>
      </section>
      <section id=contact>
        <h1>Contact</h1>
        <form>
          Name: <input required>
          Email: <input required><button>Send</button>
        </form>
      </section>
    </main>
  </body>
</html>

Another layout variation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!DOCTYPE html>
<html lang=en>
  <head>
    <meta charset=UTF-8>
    <title>Flexible Box Layout Test 7</title>
    <style>
      nav {
        display:          flex;
        background-color: #0a73a7;
      }

      ul {
        display:          flex;
        flex:             auto;
        list-style:       none;
        background-color: lightgrey;
      }

      li {
        text-align: center;
        display:    block;
      }

      #l1 {
        justify-content:  center;
        background-color: lightgreen;
      }

      #l2 {
        max-width:        130px;
        background-color: lightblue;
      }
    </style>
  </head>
  <body>
    <nav>
      <ul id=l1>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
      </ul>
      <ul id=l2>
        <li>Item 4</li>
        <li>Item 5</li>
        <li>Item 6</li>
      </ul>
    </nav>
  </body>
</html>
Grid layout

Grid layout makes it easy to build the big picture aspects of our layout, i.e. the row AND column layout. We can then use Flexbox to manage the horizontal OR vertical alignment of the content inside the grid elements.

css-tricks.com/snippets/css/complete-guide-grid

caniuse.com/\#search=Grid

www.mozilla.org/en-US/developer/css-grid

developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout

gridbyexample.com/

bitsofco.de/how-the-minmax-function-works

tutorialzine.com/2017/03/css-grid-vs-flexbox

Here’s a very simple example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<html lang=en>
  <head>
    <meta charset=UTF-8>
    <title>CSS Grid example</title>
    <style>
      html, body {
        width:  100%;
        height: 100%;
        margin: 0;
      }

      main {
        height:                100%;
        display:               grid;
        grid-template-columns: 3fr 1fr 2fr;
        grid-template-rows:    1fr 3fr;
        /*align-items:           stretch;*/
      }

      section {
        background-color: lawngreen;
        border:           darkmagenta solid 2px;
      }
    </style>
  </head>
  <body>
    <main>
      <section>One</section>
      <section>Two</section>
      <section>Three</section>
      <section>Four</section>
      <section>Five</section>
      <section>Six</section>
    </main>
  </body>
</html>

When should we use Grid and when Flexbox? This article dives into the question.

To support browsers without grid see:

www.smashingmagazine.com/2017/11/css-grid-supporting-browsers-without-grid

developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/CSS_Grid_and_Progressive_Enhancement

rachelandrew.co.uk/archives/2016/11/26/should-i-try-to-use-the-ie-implementation-of-css-grid-layout

Responsive design

Responsive web design aims at building websites that work on mobile devices, tablets, and desktop screens.

It is important to set the viewport to optimize the user’s experience:

1
<meta name=viewport content="width=device-width, initial-scale=1">

For detailed explanations see:

www.w3schools.com/css/css_rwd_viewport.asp

developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag

www.quirksmode.org/mobile/viewports.html

www.quirksmode.org/mobile/viewports2.html

www.quirksmode.org/mobile

developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries

drafts.csswg.org/mediaqueries

css-tricks.com/dont-overthink-flexbox-grids

www.w3schools.com/cssref/css3_pr_mediaquery.asp

developer.mozilla.org/en-US/docs/Web_Development/Responsive_Web_design

blog.teamtreehouse.com/modern-field-guide-responsive-web-design

screensiz.es/phone

developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag

developer.mozilla.org/en-US/docs/Web/HTML/Element/meta

webdesignerwall.com/tutorials/viewport-meta-tag-for-non-responsive-design

www.smashingmagazine.com/2011/07/22/responsive-web-design-techniques-tools-and-design-strategies

www.quirksmode.org/mobile/metaviewport

googlewebmastercentral.blogspot.co.uk/2012/04/responsive-design-harnessing-power-of.html

responsivedesign.is/develop/html/viewport-meta-element

css-tricks.com/accessible-simple-responsive-tables

In Firefox, pressing Ctrl+Shift+M or Tools  Web Developer  Responsive Design View

responsivedesignview1

Let’s look at a practical example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<!DOCTYPE html>
<html lang=en>
  <head>
    <meta charset=UTF-8>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Responsive layout example 1</title>
    <style>
      html { /* http://www.paulirish.com/2012/box-sizing-border-box-ftw */
        box-sizing: border-box;
      }

      *, *:before, *:after {
        box-sizing: inherit;
      }

      ul {
        display:    flex;
        flex-wrap:  wrap;
        padding:    0;
        list-style: none;
      }

      ul li {
        flex:       auto;
        text-align: center;
        padding:    2px;
      }

      @media (min-width: 10em) {
        ul li {
          flex-basis: 33%;
        }
      }

      @media (min-width: 28em) {
        ul li {
          flex-basis: 0;
        }
      }

      ul li a {
        display:         block;
        text-decoration: none;
      }
    </style>
  </head>
  <body>
    <nav>
      <ul>
        <li><a href=#>Item 1</a></li>
        <li><a href=#>Item 2</a></li>
        <li><a href=#>Item 3</a></li>
        <li><a href=#>Item 4</a></li>
        <li><a href=#>Item 5</a></li>
        <li><a href=#>Item 6</a></li>
      </ul>
    </nav>
    <main>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut et tempus urna. In sed
      sagittis arcu. Cras in sapien diam. Aenean massa ipsum, rutrum eu facilisis vitae,
      semper in arcu. Morbi vitae tortor sit amet turpis feugiat aliquam. Aliquam eu
      rhoncus odio, quis rutrum magna.
    </main>
  </body>
</html>
Responsive menus
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Responsive layout example 2</title>
    <meta charset=utf-8>
    <meta name=viewport content="width=device-width, initial-scale=1">
    <style>
      html { /* http://www.paulirish.com/2012/box-sizing-border-box-ftw */
        box-sizing: border-box;
      }

      *, *:before, *:after {
        box-sizing: inherit;
      }

      nav {
        margin:           4px;
        padding:          4px;
        border:           1px solid #8888bb;
        border-radius:    7pt;
        background-color: #ccccff;
        min-width:        50px;
        flex:             auto;
      }

      ul {
        display:    flex;
        flex-wrap:  wrap;
        margin:     0;
        padding:    0;
        list-style: none;
      }

      ul li {
        flex:             auto;
        text-align:       center;
        padding:          2px;
        background-color: #ffeebb;
      }

      @media (min-width: 10em) {
        ul li {
          flex-basis: 33%;
        }
      }

      @media (min-width: 28em) {
        ul li {
          flex-basis: 0;
        }
      }

      ul li a {
        display:         block;
        text-decoration: none;
      }

      html, body {
        width:  100%;
        height: 100%;
      }

      body {
        background-color: #999999;
        display:          flex;
        flex-direction:   column;
        margin:           0;
        overflow:         hidden;
      }

      main {
        margin:   0;
        padding:  0;
        display:  flex;
        flex:     auto;
        overflow: auto;
      }

      main > nav {
        margin:           4px;
        padding:          5px;
        border:           1px solid #8888bb;
        border-radius:    7pt;
        background-color: #ccccff;
        min-width:        50px;
        flex:             auto;
      }

      main > section {
        margin:           4px;
        padding:          5px;
        border:           1px solid #8888bb;
        border-radius:    7pt;
        background-color: #ccccff;
        display:          flex;
        flex-direction:   column;
        min-width:        50px;
        overflow:         hidden;
      }

      main > section > section {
        display:   flex;
        flex-flow: column;
        flex:      auto;
        overflow:  hidden;
      }

      header, footer {
        margin:           4px;
        padding:          5px;
        min-height:       50px;
        border:           1px solid #eebb55;
        border-radius:    7pt;
        background-color: #ffeebb;
      }

      #s1 {
        flex:      auto;
        flex-flow: column;
        overflow:  hidden;
      }

      #s1 > article, #s2 {
        overflow: auto;
      }

      .verticalSplitter {
        border-left: 1px solid grey;
        width:       1px;
        min-width:   1px;
        cursor:      col-resize;
      }

      .horizontalSplitter {
        border-top: 1px solid grey;
        height:     1px;
        min-height: 1px;
        cursor:     row-resize;
      }

      /* Too narrow to support three columns */
      @media all and (max-width: 640px) {
        main {
          flex-flow: column;
        }

        main > nav, header, footer {
          height: 50px;
        }

        .horizontalSplitter, .verticalSplitter {
          display: none;
        }
      }
    </style>
    <script src=flextest5.js></script>
  </head>
  <body>
    <nav>
      <ul>
        <li><a href=#>Item 1</a></li>
        <li><a href=#>Item 2</a></li>
        <li><a href=#>Item 3</a></li>
        <li><a href=#>Item 4</a></li>
        <li><a href=#>Item 5</a></li>
        <li><a href=#>Item 6</a></li>
      </ul>
    </nav>
    <main>
      <nav>nav</nav>
      <div class=verticalSplitter></div>
      <section>
        <section id=s1>
          <header>Header s1</header>
          <article><?php require 'flextest4.txt'; ?></article>
        </section>
        <div id=hs1 class=horizontalSplitter></div>
        <section id=s2><?php require 'flextest4.txt'; ?></section>
      </section>
    </main>
    <footer>footer</footer>
  </body>
</html>

Here is a hamburger icon menu example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<!DOCTYPE html>
<html lang=en>
  <head>
    <meta charset=UTF-8>
    <meta name=viewport content="width=device-width, initial-scale=1.0">
    <title>Responsive layout example 3</title>
    <style>
      /* Inspiration from http://codepen.io/ricardozea/pen/OPaRZO */
      html { /* http://www.paulirish.com/2012/box-sizing-border-box-ftw */
        box-sizing: border-box;
      }

      *, *:before, *:after {
        box-sizing: inherit;
      }

      #menu-button {
        padding:         0 0.2em 0.2em 0.2em;
        background:      #f6f6f6;
        text-decoration: none;
        color:           #333;
        cursor:          pointer;
        font-size:       3em;
      }

      #menu-button.active {
        background-color: #333;
        color:            #fff;
      }

      #menu {
        overflow:   hidden;
        max-height: 0;
        padding:    0;
        clear:      both;
        transition: all .3s ease-out;
      }

      #menu.active {
        max-height: 17em;
      }

      #menu ul {
        margin:          0;
        padding:         0;
        list-style-type: none;
        border:          1px #999 dotted;
        border-bottom:   none;
        text-align:      center;
      }

      #menu li a {
        display:          block;
        padding:          1em;
        border-bottom:    1px #999 dotted;
        text-decoration:  none;
        color:            #2963BD;
        background-color: #fff;
      }

      @media (min-width: 40em) {
        #menu-button {
          display: none;
        }

        #menu {
          max-height: inherit;
        }

        #menu ul {
          background: #fff;
        }

        #menu li {
          display: inline-block;
          margin:  0 .2em;
        }
      }
    </style>
    <script>
      'use strict';

      const init = () => {
        document.querySelector('button').addEventListener('click', () => {
          document.querySelector('button').classList.toggle('active');
          document.querySelector('#menu').classList.toggle('active');
        });
      };

      window.addEventListener('load', init);
    </script>
  </head>
  <body>
    <button id=menu-button></button>
    <nav id=menu>
      <ul>
        <li><a href=#>Item 1</a></li>
        <li><a href=#>Item 2</a></li>
        <li><a href=#>Item 3</a></li>
        <li><a href=#>Item 4</a></li>
        <li><a href=#>Item 5</a></li>
      </ul>
    </nav>
    <main>
      <section><?php require 'flextest4.txt'; ?></section>
    </main>
  </body>
</html>
Navigation menus
navigationmenu1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Navigation Menu</title>
    <meta charset=UTF-8>
    <style>
      nav {
        margin:      0;
        white-space: nowrap;
      }

      nav ul {
        padding:         0;
        margin:          0;
        list-style-type: none;
      }

      nav ul li {
        display: inline-block;
        cursor:  pointer;
      }

      nav ul li ul {
        position: absolute;
        display:  none;
      }

      nav > ul > li ul li, nav > ul > li:hover > ul {
        display: block;
      }

      nav > ul > li ul li:hover > ul {
        display: inline-block;
      }
    </style>
  </head>
  <body>
    <nav>
      <ul>
        <li>
          Menu1
          <ul>
            <li>
              Submenu1
              <ul>
                <li>Subsubmenu1</li>
              </ul>
            </li>
          </ul>
        </li>
        <li>
          Menu2
          <ul>
            <li>
              Submenu1
              <ul>
                <li>Subsubmenu1</li>
                <li>
                  Subsubmenu2
                  <ul>
                    <li>Subsubsubmenu1</li>
                    <li>
                      Subsubsubmenu2
                      <ul>
                        <li>Subsubsubsubmenu1</li>
                      </ul>
                    </li>
                    <li>Subsubsubmenu3</li>
                  </ul>
                </li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </nav>
  </body>
</html>
navigationmenu2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Navigation Menu</title>
    <meta charset=UTF-8>
    <style>
      nav a {
        text-decoration: none;
        cursor:          pointer;
        border:          2px solid blue;
      }

      nav ul {
        padding:    0;
        margin:     0;
        list-style: none;
      }

      nav > ul > li {
        float:       left;
        clear:       left;
        white-space: nowrap;
      }

      nav ul li ul {
        position:   absolute;
        display:    inline-block;
        visibility: hidden;
      }

      nav li:hover > ul {
        visibility: visible;
      }
    </style>
  </head>
  <body>
    <nav>
      <ul>
        <li>
          <a>Menu 1</a>
          <ul>
            <li>
              <a>Menu 1 Sub 1</a>
              <ul>
                <li><a>Menu 1 Sub Sub 1</a></li>
              </ul>
            </li>
          </ul>
        </li>
        <li>
          <a>Menu 2</a>
          <ul>
            <li>
              <a>Menu 2 Sub 1</a>
              <ul>
                <li><a>Menu 2 Sub Sub 1</a></li>
                <li>
                  <a>Menu 2 Sub Sub 2</a>
                  <ul>
                    <li><a>Menu 2 Sub Sub Sub 1</a></li>
                    <li>
                      <a>Menu 2 Sub Sub Sub 2</a>
                      <ul>
                        <li><a>Menu 2 Sub Sub Sub Sub 1</a></li>
                      </ul>
                    </li>
                    <li><a>Menu 2 Sub Sub Sub 3</a></li>
                  </ul>
                </li>
              </ul>
            </li>
          </ul>
        </li>
        <li>
          <a>Menu 3</a>
        </li>
        <li>
          <a>Menu 4</a>
        </li>
      </ul>
    </nav>
  </body>
</html>
navigationmenu3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Navigation Menu</title>
    <meta charset=UTF-8>
    <style>
      body {
        background: linear-gradient(red, white, blue) fixed;
      }

      nav {
        position:   absolute;
        top:        0;
        left:       0;
        transition: 50s;
      }

      nav:hover {
        left: 500px;
        top:  500px;
      }

      nav a {
        text-decoration:       none;
        cursor:                pointer;
        padding:               5px;
        background:            radial-gradient(rgb(0, 255, 0), rgb(255, 0, 255));
        display:               inline-block;
        border:                2px outset black;
        /* stackoverflow.com/questions/826782/css-rule-to-disable-text-selection-
        highlighting */
        -webkit-touch-callout: none;
        -webkit-user-select:   none;
        -khtml-user-select:    none;
        -moz-user-select:      none;
        -ms-user-select:       none;
        /*user-select:           none;*/
      }

      nav a:hover {
        background-color: green;
      }

      nav ul {
        padding:    0;
        margin:     0;
        list-style: none;
      }

      nav > ul ul li {
        padding-left: 10px;
      }

      nav > ul ul li:before {
        content:       '';
        position:      absolute;
        left:          1px;
        top:           9px;
        border-bottom: 8px solid transparent;
        border-top:    8px solid transparent;
        border-left:   8px solid lightgreen;
      }

      nav > ul > li {
        float:       left;
        clear:       left;
        white-space: nowrap;
      }

      nav ul li ul {
        position: absolute;
        display:  none;
      }

      nav > ul li:hover > ul {
        display: inline-block;
      }
    </style>
  </head>
  <body>
    <nav>
      <ul>
        <li>
          <a>Menu 1</a>
          <ul>
            <li>
              <a>Menu 1 Sub 1</a>
              <ul>
                <li><a>Menu 1 Sub Sub 1</a></li>
              </ul>
            </li>
          </ul>
        </li>
        <li>
          <a>Menu 2</a>
          <ul>
            <li>
              <a>Menu 2 Sub 1</a>
              <ul>
                <li><a>Menu 2 Sub Sub 1</a></li>
                <li>
                  <a>Menu 2 Sub Sub 2</a>
                  <ul>
                    <li><a>Menu 2 Sub Sub Sub 1</a></li>
                    <li>
                      <a>Menu 2 Sub Sub Sub 2</a>
                      <ul>
                        <li><a>Menu 2 Sub Sub Sub Sub 1</a></li>
                      </ul>
                    </li>
                    <li><a>Menu 2 Sub Sub Sub 3</a></li>
                  </ul>
                </li>
              </ul>
            </li>
          </ul>
        </li>
        <li>
          <a>Menu 3</a>
        </li>
        <li>
          <a>Menu 4</a>
        </li>
      </ul>
    </nav>
  </body>
</html>

A useful tutorial and templates can be found at cssmenumaker.com/blog/responsive-menu-tutorial.

4.2.8. Make it look good

Gradients

Gradients are a great alternative to standard images. www.w3schools.com/css/css3_gradients.asp and developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_gradients provide excellent information and examples on the subject. The official specification can be found at dev.w3.org/csswg/css-images-3.

Example:

gradient1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Gradient example 1</title>
    <meta charset=UTF-8>
    <style>
      body {
        background: repeating-radial-gradient(red, blue 20px, red 40px) fixed;
      }

      section {
        position: absolute;
        width: 500px;
        height: 500px;
        background: linear-gradient(90deg, black, transparent, white);
        border-radius: 100px;
      }

      article {
        width: 30px;
        height: 30px;
        background: repeating-linear-gradient(-45deg, red, red 5px, white 5px, white 10px);
        border-radius: 15px;
      }
    </style>
  </head>
  <body>
    <main>
      <section>
        <article>

        </article>
      </section>
    </main>
  </body>
</html>

An excellent gradient generator can be found at www.colorzilla.com/gradient-editor.

Buttons

With CSS3 it’s very easy to create great looking buttons without using pictures. There are many button generators available on the Web that produce nice results, for instance:

www.cssbuttongenerator.com

dabuttonfactory.com

css3button.net

Transformation and animation

For examples of what can be done, take a look at the following:

www.marcofolio.net/css/css_animated_profile_cards.html

www.marcofolio.net/css/animated_wicked_css3_3d_bar_chart.html

3dtransforms.desandro.com

To find out which CSS properties can be animated, take a look at developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties.

Here is a simpler example:

animation1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Animation example 1</title>
    <meta charset=UTF-8>
    <style>
      body {
        background: repeating-radial-gradient(red, blue 20px, red 40px) fixed;
      }

      section {
        position:          absolute;
        width:             500px;
        height:            500px;
        background:        linear-gradient(90deg, black, transparent, white);
        animation:         sectionAnimation 5s infinite alternate;
        border-radius:     100px;
      }

      @keyframes sectionAnimation {
        from {
          left: 0;
          top:  0;
        }
        to {
          left: 500px;
          top:  100px;
        }
      }

      aside {
        position:          absolute;
        width:             30px;
        height:            30px;
        background:        repeating-linear-gradient(-45deg, red, red 5px, white 5px, white 10px);
        border-radius:     15px;
        animation:         asideAnimation 5s infinite alternate;
      }

        /* Standard syntax */
      @keyframes asideAnimation {
        0% {
          left: 500px;
          top:  0;
        }

        50% {
          left: 250px;
          top:  300px;
        }

        100% {
          left: 0px;
          top:  100px;
        }
      }
    </style>
  </head>
  <body>
    <main>
      <section></section>
      <aside></aside>
    </main>
  </body>
</html>
Fonts

websitesetup.org/web-safe-fonts-html-css

www.typewolf.com/google-fonts

www.dvginteractive.com/serif-vs-sans-serif-how-to-increase-your-websites-readability-by-more-than-50-2

@font-face

You can find lots of free fonts at www.google.com/fonts. Also read www.creativebloq.com/typography/free-web-fonts-1131610.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Using the @font-face rule</title>
    <meta charset=utf-8>
    <link href=http://fonts.googleapis.com/css?family=Shadows+Into+Light rel=stylesheet>
    <style>
      body {
        font-family: 'Shadows Into Light', cursive;
      }
    </style>
  </head>
  <body>
    <main>
      <h1>Test header</h1>
    </main>
  </body>
</html>

4.2.9. Quiz

Take the w3schools quiz at www.w3schools.com/quiztest/quiztest.asp?qtest=CSS as a fun way to check you are as good as you think you are.

4.2.10. Tests

Computer Shop
ComputerShop

Create the following validated page:

The following information is not complete:

  1. body: no margin and padding, background from black to grey, font color white, black shadow of 2 pixels h, v and blur.

  2. header: height of 100 pixels.

  3. nav: 150 pixels wide.

  4. main: right padding of 10 pixels, overflow auto.

  5. footer: 20 pixels high, font size half normal.

  6. ul with no margin and padding.

  7. li with 10 pixels padding above and below.

  8. Hyperlinks with color gold and 1 pixel black shadow h, v and blur.

  9. Navigation hyperlinks with font size twice normal.

  10. h1 with color gold and font size three times normal.

  11. Definition term with color hex 22bb22, bottom border of 2 pixels blueviolet, top margin of 10 pixels and bottom margin of 5 pixels.

  12. Table data items padding of 20 pixels.

You can copy paste the following text:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Computer Shop
Buy

Contact us

Welcome to our shop.

We offer the following:

Desktops

A desktop computer is a personal computer in a form intended for regular use at a single location desk/table due to its size and power requirements (cf. http://en.wikipedia.org/wiki/Desktop\_computer Wikipedia).

Laptops

A laptop or a notebook is a portable personal computer with a clamshell form factor, suitable for mobile use. There was a difference between laptops and notebooks in the past, but nowadays it has gradually died away. Laptops are commonly used in a variety of settings, including at work, in education, and for personal multimedia.
A laptop combines the components and inputs of a desktop computer, including display, speakers, keyboard and pointing device (such as a touchpad or a trackpad) into a single device. Most modern-day laptops also have an integrated webcam and a microphone. A laptop can be powered either from a rechargeable battery, or by mains electricity via an AC adapter. Laptop is a diverse category of devices and other more specific terms, such as rugged notebook or convertible, refer to specialist types of laptops, which have been optimized for specific uses. Hardware specifications change significantly between different types, makes and models of laptops (cf. http://en.wikipedia.org/wiki/Laptop Wikipedia).

Device

Brand

Price

LTAM

299.99

LTAM

349.99

2015 LTAM T0IF2
Solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Computer Shop</title>
    <meta charset=utf-8>
    <style>
      body {
        margin:      0;
        padding:     0;
        background:  linear-gradient(to bottom right, black, grey) fixed;
        color:       white;
        text-shadow: 2px 2px 2px black;
      }

      header {
        position: fixed;
        width:    100%;
        height:   100px;
      }

      nav {
        position: fixed;
        top:      100px;
        width:    150px;
      }

      main {
        position:      fixed;
        top:           100px;
        left:          150px;
        right:         0;
        bottom:        20px;
        text-align:    justify;
        padding-right: 10px;
        overflow:      auto;
      }

      footer {
        position:   fixed;
        bottom:     0;
        width:      100%;
        height:     20px;
        text-align: center;
        font-size:  0.5em;
      }

      ul {
        margin:  0;
        padding: 0;
      }

      li {
        padding-top:    10px;
        padding-bottom: 10px;
      }

      a {
        text-decoration: none;
        color:           gold;
        text-shadow:     1px 1px 1px black;
      }

      nav a {
        font-size: 2em;
      }

      h1 {
        text-align: center;
        font-size:  3em;
        color:      gold;
      }

      dt {
        color:         #22bb22;
        border-bottom: 2px dashed blueviolet;
        margin-top:    10px;
        margin-bottom: 5px;
      }

      th {
        text-align: center;
      }

      td {
        padding: 20px;
      }
    </style>
  </head>
  <body>
    <header>
      <h1>Computer Shop</h1>
    </header>
    <nav>
      <ul>
        <li><a href=#>Buy</a></li>
        <li><a href=#>Contact us</a></li>
      </ul>
    </nav>
    <main>
      <h2>Welcome to our shop.</h2>
      We offer the following:
      <dl>
        <dt>Desktops</dt>
        <dd>A desktop computer is a personal computer in a form intended for regular use at a
          single location desk/table due to its size and power requirements (cf. <a
            href=http://en.wikipedia.org/wiki/Desktop_computer target=_blank>Wikipedia</a>).
        </dd>
        <dt>Laptops</dt>
        <dd>A laptop or a notebook is a portable personal computer with a clamshell form
          factor, suitable for mobile use. There was a difference between laptops and
          notebooks in the past, but nowadays it has gradually died away. Laptops are
          commonly used in a variety of settings, including at work, in education, and for
          personal multimedia.
          A laptop combines the components and inputs of a desktop computer, including display,
          speakers, keyboard and pointing device (such as a touchpad or a trackpad) into a
          single device. Most modern-day laptops also have an integrated webcam and a
          microphone. A laptop can be powered either from a rechargeable battery, or by mains
          electricity via an AC adapter. Laptop is a diverse category of devices and other more
          specific terms, such as rugged notebook or convertible, refer to specialist types of
          laptops, which have been optimized for specific uses. Hardware specifications change
          significantly between different types, makes and models of laptops (cf. <a
            href=http://en.wikipedia.org/wiki/Laptop target=_blank>Wikipedia</a>).
        </dd>
      </dl>
      <table>
        <tr>
          <th>Device</th>
          <th>Brand</th>
          <th>Price</th>
        </tr>
        <tr>
          <td><img src=1432254774_mycomputer.png alt=Comp1></td>
          <td>LTAM</td>
          <td>299.99 &euro;</td>
        </tr>
        <tr>
          <td><img src=1432254808_Computer2.png alt=Comp2></td>
          <td>LTAM</td>
          <td>349.99 &euro;</td>
        </tr>
      </table>
    </main>
    <footer>&copy; 2015 LTAM T0IF2</footer>
  </body>
</html>
Video Viewer
VideoViewer

Create the validated site exactly as shown:

It consists of 2 HTML files (index.html and viewer.html) and one CSS file.

The following information is not complete:

  1. Form data is sent to the file viewer.html.

  2. The form box has a black shadow of 3 pixels h, v and blur.

  3. The user name field is focused automatically when the page is loaded.

  4. html and body have no margin and padding and use the whole browser window width and height.

  5. body: repeating radial gradient from black to yellow 100px to white 200px, white text shadow of 2 pixels h, v and blur.

  6. nav: 40 pixels high, full width.

  7. main: display flex, full width. In index.html, there is no navigation, so main starts at the top. Therefore the login box is centered.

  8. footer: 15 pixels high, font size half normal.

  9. ul with 10 px horizontal and no vertical margin. No padding.

  10. Navigation links with 10 pixel padding, 2 pixel golden border.

  11. The form has automatic margin.The animation lasts 5 seconds and starts with 0 opacity.

  12. Form inputs have 0.5 opacity and white text shadow of 2 pixels h, v, and blur.

  13. The table takes 20% of the total width and has a margin of 5 pixels.

  14. Table headings have red text color and a font size 25% bigger than normal.

  15. The iframe takes 80% of the total width and also has a margin of 5 pixels.

You can copy paste the following text:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Login

Title
Module
Link

Windows 7 installation
SYSEX1
https://www.youtube.com/embed/NP3cPmC-08A

Computer Shop
HTSTA
https://www.youtube.com/embed/C99FqKlnD1s

T1IF Invaders
CLISS2
https://www.youtube.com/embed/c--I9podO0s

2015 WMOTU
Solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Video Viewer</title>
    <meta charset=utf-8>
    <link href=style.css rel=stylesheet>
    <style>
      main {
        top: 0;
      }
    </style>
  </head>
  <body>
    <main>
      <form action=viewer.html>
        <fieldset>
          <legend>Login</legend>
          <input placeholder="user name" required autofocus>
          <input type=password placeholder=password required>
          <button>Login</button>
        </fieldset>
      </form>
    </main>
    <footer>&copy; 2015 WMOTU</footer>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Video Viewer</title>
    <meta charset=utf-8>
    <link href=style.css rel=stylesheet>
  </head>
  <body>
    <nav>
      <ul>
        <li><a href=index.html>Log out</a></li>
        <li><a
          href="mailto:t0if2@ltam.lu?subject=Information%20request">Contact us</a></li>
      </ul>
    </nav>
    <main>
      <table>
        <thead>
          <tr>
            <th>Title</th>
            <th>Module</th>
            <th>Link</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>Windows 7 installation</td>
            <td>SYSEX1</td>
            <td><a href=https://www.youtube.com/embed/NP3cPmC-08A target=myFrame>View</a></td>
          </tr>
          <tr>
            <td>Computer Shop</td>
            <td>HTSTA</td>
            <td><a href=https://www.youtube.com/embed/C99FqKlnD1s target=myFrame>View</a></td>
          </tr>
          <tr>
            <td>T1IF Invaders</td>
            <td>CLISS2</td>
            <td><a href=https://www.youtube.com/embed/c--I9podO0s target=myFrame>View</a></td>
          </tr>
        </tbody>
      </table>
      <iframe name=myFrame></iframe>
    </main>
    <footer>&copy; 2015 WMOTU</footer>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
}

body {
  background: repeating-radial-gradient(black, yellow 100px, white 200px) fixed;
  text-shadow: 2px 2px 2px white;
}

nav {
  position: fixed;
  top: 0;
  width: 100%;
  height: 40px;
}

main {
  position: fixed;
  top: 40px;
  width: 100%;
  bottom: 15px;
  display: flex;
  overflow: auto;
}

footer {
  position: fixed;
  bottom: 0;
  width: 100%;
  height: 15px;
  text-align: center;
  font-size: 0.5em;
}

nav > ul {
  list-style: none;
  margin: 10px 0;
  padding: 0;
}

nav > ul > li {
  display: inline;
}

nav > ul > li > a {
  padding: 10px;
  background-color: black;
  border: 2px inset gold;
  color: gold;
}

nav > ul > li > a:hover {
  background-color: blue;
}

a {
  text-decoration: none;
}

form {
  margin: auto;
  box-shadow: 3px 3px 3px black;
  animation: formAnim 5s;
}

@keyframes formAnim {
  from {
    opacity: 0;
  }
}

form input {
  opacity: 0.5;
  text-shadow: 2px 2px 2px white;
}

table {
  width: 20%;
  margin: 5px;
}

iframe {
  border: none;
  width: 80%;
  margin: 5px;
}

th {
  color: red;
  font-size: 1.25em;
}

4.3. JavaScript

4.3.1. Introduction to programming

In order to tell a computer what to do, we use a special language, called a "programming" language. Like "human" languages, this is a set of instructions that are translated into codes that have specific meaning to the computer.

More formally, according to en.wikipedia.org/wiki/Computer_programming:

Computer programming (often shortened to programming) is a process that leads from an original formulation of a computing problem to executable programs. It involves activities such as analysis, understanding, and generically solving such problems resulting in an algorithm, verification of requirements of the algorithm including its correctness and its resource consumption, implementation (commonly referred to as coding) of the algorithm in a target programming language. Source code is written in one or more programming languages (such as C, C++, C#, Java, Python, Smalltalk, JavaScript, etc.). The purpose of programming is to find a sequence of instructions that will automate performing a specific task or solve a given problem. The process of programming thus often requires expertise in many different subjects, including knowledge of the application domain, specialized algorithms and formal logic.

4.3.2. Getting started with JavaScript

JavaScript is the programming language used to interact with the Document Object Model (DOM) that the browser creates from HTML and CSS files. It thereby allows the programmatic control of the web page’s appearance and behavior on the client side. It is also increasingly used on the server side with Node.js. It is the foundation for the development of full fledged web applications.

javascript

JavaScript is based on the ECMAScript language specification, the latest version of which can be found at (cf. www.ecma-international.org/ecma-262). Browser support is excellent (cf. kangax.github.io/compat-table/es2016plus).

A number of very insightful articles on JavaScript can be found at javascript.crockford.com/javascript.html.

To get an in-depth overview of the latest developments in the real world application of JS, have a look at The state of JavaScript.

An excellent free online book on ECMAScript 5 can be found at speakingjs.com/es5/index.html.

To find out what’s new in ECMAScript 6 take a close look at the following resources:

Before we get started, open the console of your browser.

Firefox Chrome Internet Explorer

Console

Shift+F2

Ctrl+Shift+J or I

F12

console1
You should always keep the console open, as any error messages will only be visible there.

4.3.3. Adding JavaScript to HTML documents

The HTML tag to include a script is, for obvious reasons, the <script> tag. The user has the possibility to disable JavaScript in his browser. There’s nothing we can do about this except detect it using the <noscript> tag and inform the user that our app won’t run without JavaScript. In Firefox, you can disable JavaScript by going to the page about:config and setting javascript.enabled to false. Now run the example and turn JavaScript back on and rerun the example:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Detect whether JavaScript is disabled</title>
    <meta charset=utf-8>
  </head>
  <body>
    <main>
      <noscript>Sorry, but this application requires JavaScript to run!</noscript>
    </main>
  </body>
</html>
External JavaScript

The most common approach is to create a separate file with the extension .js (the extension is not mandatory, but recommended) and include it in the HTML file. Here’s an example:

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Using external JS</title>
    <meta charset=utf-8>
    <script src=js1.js></script>
  </head>
  <body></body>
</html>
1
2
3
"use strict";

alert('Hello world!'); // Display a message box with the text 'Hello world!'.

The strict mode "use strict"; instruction turns on strict mode (cf. Strict mode), which we should always do in order to make our life easier and to write better quality code. You can put this instruction into the default JavaScript template of your IDE, so that you do not have to type it in every time (cf. NetBeans templates or PhpStorm templates).

The <script> tag can be placed into the document’s head or body. Remember that your browser processes an HTML document from top to bottom. So if the script is put into the head, it is loaded and executed before the HTML body exists. If the script tries to access HTML elements, it will fail, as shown in this example (remember, you need to have the console open to see the error):

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Using external JS the wrong way</title>
    <meta charset=utf-8>
    <script src=js2.js></script>
  </head>
  <body><main></main></body>
</html>
1
2
3
4
5
6
7
8
9
10
"use strict";

// Save the first (and only) main element in a constant named main.
const main = document.getElementsByTagName('main')[0];
// Set the text color of the main element to gold.
main.style.color = 'gold';
// Set the background color of the main element to black.
main.style.backgroundColor = 'black';
// Set the text 'Hello world!' as content of the main element.
main.innerHTML = 'Hello world!';

Here is the error message you should see:

firebug1

One solution to this problem is to include the script at the end of the HTML document, but this is not recommended, as it is difficult to see which script gets included. A cleaner approach is to have the script loaded in the head of the document but put all instructions that should be executed immediately into a function (don’t worry, we’ll look at those in detail in JS functions, but for now you just need to know that a function is a series of instructions that get executed when we "call" the function using its name) which gets run when the browser has either finished loading and parsing the initial HTML document, without waiting for stylesheets, images, and subframes to finish loading or when the full document has been loaded and parsed. To achieve the former, we use the DOMContentLoaded (cf. developer.mozilla.org/en/docs/Web/Events/DOMContentLoaded) and for the latter the load event (cf. Events where we talk about events in detail):

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Using external JS the right way</title>
    <meta charset=utf-8>
    <script src=js3.js></script>
  </head>
  <body><main></main></body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"use strict";

// We declare but do not execute the function.
const init = () => {
  const main = document.querySelector('main'); // Get the main element.
  main.style.color = 'gold'; // Set text color to gold.
  main.style.backgroundColor = 'black'; // Set background color to black.
  main.innerHTML = 'Hello world!'; // Set main content.
};

/* Only after the browser has finished loading and parsing the initial HTML document, without
 waiting for stylesheets, images, and subframes or the whole document,
 meaning that the DOM is available, will the init function be called.
 There are 2 events we can use and 2 ways to do this. The first one is the preferred one, as it
 allows to install several listeners for the same event. The second one is shorter. */
window.addEventListener('DOMContentLoaded', init);
//window.addEventListener('load', init);
//window.onload = init;
async and defer

The async attribute is only for external scripts (and should only be used if the src attribute is present).

Note: There are several ways an external script can be executed:

  • If async is present: The script is executed asynchronously with the rest of the page (the script will be executed while the page continues the parsing).

  • If async is not present and defer is present: The script is executed when the page has finished parsing.

  • If neither async or defer is present: The script is fetched and executed immediately, before the browser continues parsing the page.

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Using external JS the right way</title>
    <meta charset=utf-8>
    <script src=js3a.js defer></script>
  </head>
  <body><main></main></body>
</html>
1
2
3
4
5
6
"use strict";

const main = document.querySelector('main'); // Get the main element.
main.style.color = 'gold'; // Set text color to gold.
main.style.backgroundColor = 'black'; // Set background color to black.
main.innerHTML = 'Hello world!'; // Set main content.
Embedded JavaScript

If we have only a small script that we want to use in our document, we can embed it directly using the <script> tag, like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Using embedded JS</title>
    <meta charset=utf-8>
    <script>
      "use strict";

      const sayHello = () => {
        alert('Hello world!');
      };

      window.addEventListener('load', sayHello);
    </script>
  </head>
  <body></body>
</html>

We can embed JavaScript in the head and/or in the body part of the document.

Inline JavaScript

If we need to execute only one or very few instructions, for instance when a link is clicked, we can use JavaScript inline as an event handler (cf. Events).

Here’s a simple illustration using a clickable link:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Using inline JS</title>
    <meta charset=utf-8>
  </head>
  <body>
    <main>
      <a href=# onclick="alert('Hello world!');">
        If you click me I'll greet the world!</a>
    </main>
  </body>
</html>
Combinations

In the real world, you will often use combinations of some or all of the three methods, for instance an external script that defines functions, which are called via embedded or inline script.

Here is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Combining external and inline JS</title>
    <meta charset=utf-8>
    <script src=js6.js></script> <!-- include an external script -->
  </head>
  <body>
    <main>
      <a href=# onclick=modifyMain();>If you click me I'll change the world!</a>
    </main>
  </body>
</html>
1
2
3
4
5
6
7
8
"use strict";

const modifyMain = () => {
  const main = document.getElementsByTagName('main')[0];
  main.style.color = 'gold';
  main.style.backgroundColor = 'black';
  main.innerHTML = 'Hello world!';
};

4.3.4. Comments

In order to make our scripts easier to understand, it is a good idea to add comments that explain what the purpose of a piece of code is if it is not obvious. Comments should not repeat the code or explain trivialities. JavaScript provides single line comments using // and multiline comments using /* */. You have already seen examples of both in External JavaScript.

4.3.5. Semicolons

Most ECMAScript statements and declarations must be terminated with a semicolon. Such semicolons may always appear explicitly in the source text. For convenience, however, such semicolons may be omitted from the source text in certain situations. These situations are described by saying that semicolons are automatically inserted into the source code token stream in those situations.

In order to avoid needless errors, we’ll always terminate the JS statements listed above with semicolons.

4.3.6. Basic input and output

console.log

The console object provides access to the browser’s debugging console, which we use to detect errors in our programs. For the details see developer.mozilla.org/en-US/docs/Web/API/console and developer.mozilla.org/en-US/docs/Tools/Web_Console.

Here is a simple example:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Console usage example</title>
    <meta charset=utf-8>
    <script src=console1.js></script>
  </head>
  <body>
  </body>
</html>
document.write

document.write writes a given text verbatim into the document at the current position. Example: students.btsi.lu/evegi144/WAD/JS/document_write1.html

1
2
3
4
5
"use strict";

document.write('<table><tr><th>Club</th><th>Score</th></tr>');
document.write('<tr><td>Bayern München</td><td>17</td></tr>');
document.write('<tr><td>FC Liverpool</td><td>15</td></tr></table>');
alert

In some of the previous examples we have already used the alert method. This method is part of the global window object, which we’ll discuss in Browser Object Model (BOM). Normally we would have to write window.alert to use this method, but the browser considers window as the default object, thereby allowing us to simply write the method name. alert takes the text, quoted in "" or '', as parameter and displays it in a dialog box, which will block the screen until the user confirms the message.

confirm

The confirm method, just like alert, displays a dialog box with a specified message, but with an OK and a Cancel button, so that the user has a choice. The method returns true if the user clicked OK and false if the user clicked Cancel. Example:

1
2
3
4
5
6
7
"use strict";

if (confirm('Do you really want to format your hard drive?') === true)
  console.log('OK, as you wish!');
else {
  console.log('Pweh!');
}
prompt

prompt is used to get input from the user. The first parameter specifies the text to display. The second parameter is optional and can be used to display a default value. Take a look at the example and experiment with it. Note the \' in the prompt message. This is used to tell the browser that the apostrophe does not terminate the string but is to be displayed as such:

1
2
3
4
5
"use strict";

const input = prompt('Congratulations, you\'re the master of the universe. ' +
  'Please enter your name:', 'Donald Duck');
if (input) console.log(`Well done ${input}`);

4.3.7. Constants

If we want to use a specific immutable value throughout our script, we can declare it as a constant using const. Constants have block scope, i.e. they are only visible within the block that they are defined. If we define a constant in the main part of our script it will be visible everywhere. The advantage of using the constant compared to using the value directly is the ease with which we can change it.

For instance, if we decide that the player in our latest space shooter should have 5 lives instead of 3, we simply change the value of our constant. Without constant we would have to find all the occurrences of the value in our script and replace them individually, risking to accidentally change other values.

1
2
const LIVES = 3;
console.log(LIVES);

4.3.8. Variables

A program spends most of its time manipulating some kind of data, e.g. integer and decimal (or floating point) numbers, text (called string) or other, potentially more complex, data types. The information we need, for internal calculations or for display to the user, has to be stored somehow. To store data, we use variables. A variable is simply a place in computer memory where some information is stored.

To work with a variable we first need to declare it using the let or var keyword. The former has block scope whereas the latter has function scope. For an illustration of the difference, see let vs var. For a more detailed explanation with examples see developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/let. After declaration the variable value is undefined. We can store some information in it using the = operator. Let’s take a look at an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"use strict";

// We want to recalculate the health of our spaceship after it has been hit by an enemy bullet.
// We declare the variable for the initial health level and assign it a value of 100.
let health; // Declare a variable with block scope. Default value undefined.
alert(`Current health: ${health}`); //
health = 100; // We assign the value 100 to the variable.
alert(`Current health: ${health}`);
/* We declare a constant to store the damage caused by an enemy bullet hit. A constant cannot
be changed. */
const SHOT_IMPACT = 20;

// *** Boom, we have been hit ***
// Now we calculate the new health value
health = health - SHOT_IMPACT;
alert(`We've been hit! Current health: ${health}`);
Variable names
  • Variable names can contain letters, digits, underscores, and dollar signs.

  • Variable names must begin with a letter.

  • Variable names can also begin with $ and _.

  • Variable names are case sensitive (y and Y are different variables).

  • Reserved words (like JavaScript keywords) cannot be used as variable names.

It is recommended to use camelCase, e.g. firstFraction instead of first_fraction or firstfraction etc. Please read the quick overview of JavaScript code conventions at www.w3schools.com/js/js_conventions.asp.

4.3.9. Data types

JavaScript is a dynamically typed language, meaning that we can store any type of data in a variable or pass it as an argument to a function. This is in contrast to traditional programming languages such as C, C++, Java etc. Nevertheless, we need to be aware of the main data types that we will use. In our programs we can use the typeof operator to determine the current type of a variable, as in this example:

1
2
3
4
5
6
7
8
9
10
"use strict";

let x = 7; // integer number
console.log(`Current type of x: ${typeof x}`);
x = 5.6e-2; // decimal number
console.log(`Current type of x: ${typeof x}`);
x = 'abc sdfsd'; // string
console.log(`Current type of x: ${typeof x}`);
x = false; // boolean
console.log('Current type of x: ' + typeof x);
Strings

A string is simply text, i.e. a sequence of one or more characters. Strings are always embedded within simple (') or double (") quotes. We can combine several strings using the + operator, as shown in the examples below. Strings have a number of properties and methods that make working with them much easier. Study www.w3schools.com/jsref/jsref_obj_string.asp for a full reference with many examples.

Examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
"use strict";

const s1 = 'This is a string';
/* Now we write the combination of two strings, which is a new string, into the body.
 Note that we use the + operator to concatenate, i.e. to combine, three strings. */
document.body.innerHTML = `<p>Content of constant s1: ${s1}</p>`;

let firstName = 'Donald', lastName = 'Duck';
document.body.innerHTML += `<p>Hello ${firstName} ${lastName}, how are you today?</p>`;
firstName = 'Dagobert'; // We change the content of this variable.
document.body.innerHTML += `<p>Hello ${firstName} ${lastName}, how are you today?</p>`;
document.body.innerHTML += `<p>Hello ${firstName} ${lastName.toUpperCase()}, how are you
today?</p>`;
Numbers

JavaScript does not distinguish between integers and decimals. Numbers are always stored as double precision floating point numbers, following the international IEEE 754 standard. This format stores numbers in 64 bits, where the number (the fraction) is stored in bits 0 to 51, the exponent in bits 52 to 62, and the sign in bit 63 (cf. www.w3schools.com/js/js_numbers.asp). This has practical implications, some of which are problematic. It leads for instance to mathematical imprecision, which you can confirm by typing 0.1 + 0.2 in the console. To avoid this problem, we can use decimal.js. This problem is however common in almost all programming languages and not limited to JS. For details on the problem in different programming languages see 0.30000000000000004.com.

Numbers have properties and methods that make working with them much easier. Study www.w3schools.com/jsref/jsref_obj_number.asp for a full reference with many examples.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
"use strict";

// We declare 4 variables and initialize them with 2 integer and 2 decimal numbers.
const i1 = 5000, i2 = 7345, d1 = 32.456787, d2 = -2.3e5; // exponential notation -> 2.3 * 10^5
/* We display their values as well as the results of simple operations.
   Note that the + operator automatically converts the value after the + into a string if
   the value in front of the + is a string.
   On the other hand, if there is nothing in front of the + operator and it is followed by a
   string, then this string will be converted to a number, if possible, otherwise to NaN
   (not a number).
 */
console.log(`i1: ${i1} i2: ${i2} d1: ${d1} d2: ${d2}`);
/* Note that we need to put the calculations into parentheses, otherwise i1 + i2 would
 give the string '50007345'. Try it!
  */
console.log('i1 + i2: ' + (i1 + i2));
console.log(`i1 - i2: ${i1 - i2}`);
console.log('i1 / i2: ' + (i1 / i2));
console.log(`i1 * i2: ${i1 * i2}`);
console.log('d1 + d2: ' + (d1 + d2));
console.log(`d1 - d2: ${d1 - d2}`);
console.log('d1 / d2: ' + (d1 / d2));
console.log(`d1 * d2: ${d1 * d2}`);

let input1 = prompt('Please enter your first number: ');
let input2 = prompt('Please enter your second number: ');
console.log(`input1: ${input1} input2: ${input2}`);
console.log(`input1 + input2: ${input1 + input2}`);
console.log(`input1 - input2: ${input1 - input2}`);
console.log(`input1 / input2: ${input1 / input2}`);
console.log(`input1 * input2: ${input1 * input2}`);
console.log('Oops! Something went wrong. Can you spot the problem?');
console.log('Apparently the + operator treats our numbers as strings!');
console.log("Let's fix it:");
input1 = parseFloat(input1); // Convert string to floating point number.
input2 = parseFloat(input2); // Ditto.
console.log(`input1: ${input1} input2: ${input2}`);
console.log(`input1 + input2: ${input1 + input2}`);
console.log(`input1 - input2: ${input1 - input2}`);
console.log(`input1 / input2: ${input1 / input2}`);
console.log(`input1 * input2: ${input1 * input2}`);

console.log('Problem:');
// Given the limited precision of floating point numbers, we need to be careful with decimals.
let i = 0;
// The toFixed() method converts a number into a string with a specified number of decimals.
console.log(`i: ${i} i.toFixed(1): ${i.toFixed(1)}`);
i = i + 0.2;
console.log(`i: ${i} i.toFixed(1): ${i.toFixed(1)}`);
i = i + 0.2;
console.log(`i: ${i} i.toFixed(1): ${i.toFixed(1)}`);
i = i + 0.2;
console.log(`i: ${i} i.toFixed(1): ${i.toFixed(1)}`);
i = i + 0.2;
console.log(`i: ${i} i.toFixed(1): ${i.toFixed(1)}`);
i = i + 0.2;
console.log(`i: ${i} i.toFixed(1): ${i.toFixed(1)}`);
i = i + 0.2;
console.log(`i: ${i} i.toFixed(1): ${i.toFixed(1)}`);
i = i + 0.2;
console.log(`i: ${i} i.toFixed(1): ${i.toFixed(1)}`);
i = i + 0.2;
console.log(`i: ${i} i.toFixed(1): ${i.toFixed(1)}`);
i = i + 0.2;
console.log(`i: ${i} i.toFixed(1): ${i.toFixed(1)}`);
i = i + 0.2;
console.log(`i: ${i} i.toFixed(1): ${i.toFixed(1)}`);
console.log('The same with a loop:');
// This is a for loop, which we'll discuss later.
for (let i = 0; i < 2; i += .2) console.log(`i: ${i} i.toFixed(1): ${i.toFixed(1)}`);
Booleans

A boolean value is either true or false (cf. www.w3schools.com/js/js_booleans.asp). This data type is used in conditions and comparisons. Example:

1
2
3
4
5
6
"use strict";

const flag = true, x = 7, y = 34.6;
console.log(flag);
console.log(`x: ${x} y: ${y} => x is bigger than y: ${x > y}`);
console.log(`x - y + 20 is negative: ${(x - y + 20) < 0}`);
Conversions

JavaScript provides several options to convert between data types. To convert strings into numbers, we can put the + operator in front of the string. If the string cannot be fully converted into a number, the result will be NaN, meaning not a number. To transform user input into a number, it is usually preferable to use parseInt or parseFloat. These functions take a string as input and return an integer or a decimal (float, shortcut for floating point number). The advantage of these functions is that even if there are non-numerical characters in the string, as long as there is at least one digit at the beginning of the string, they will return a number and simply ignore the other characters. To convert anything into a string, we can use toString, which is a method that every object has by default. Let’s look at a couple of examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"use strict";

const a1 = '66.76', a2 = '5'; // Declare and define 2 string variables.
console.log(a1 + a2); // Concatenation of 2 strings.
console.log(+a1 + +a2); // Conversion to numbers.
const s1 = prompt('Please enter your first number: '); // string 1
const s2 = prompt('Please enter your second number: '); // string 2
console.log(s1 + s2); // Concatenation of 2 strings.
console.log(parseInt(s1) + parseInt(s2)); // Conversion to integers.
console.log(parseFloat(s1) + parseInt(s2)); // Conversion to 1 float + 1 int.
console.log(parseInt(s1) + parseFloat(s2)); // Conversion to 1 int + 1 float.
console.log(parseFloat(s1) + parseFloat(s2)); // Conversion to floats.
const x1 = 123, x2 = 456; // Declare and define 2 number variables.
console.log(x1 + x2); // Addition of 2 numbers.
console.log(x1.toString() + x2); // Conversion to strings.
console.log(x1 + x2.toString()); // Conversion to strings.
console.log(x1.toString() + x2.toString()); // Conversion to strings.
const b1 = false, b2 = true; // Declare and define 2 booleans.
console.log(b1 + b2); // Addition of 2 booleans (0 + 1 -> 1).
console.log(b1.toString() + b2); // Conversion to strings.
console.log(b1 + b2.toString()); // Conversion to strings.
console.log(b1.toString() + b2.toString()); // Conversion to strings.
Math

The Math object offers a number of useful methods. Study www.w3schools.com/js/js_math.asp and www.w3schools.com/jsref/jsref_obj_math.asp.

Regular expressions

Regular expressions provide a very powerful means to search for patterns in strings. Study www.w3schools.com/js/js_regexp.asp and www.w3schools.com/js/js_regexp.asp.

Maps and sets

4.3.10. Operators

Study the JavaScript operator documentation on w3schools: www.w3schools.com/js/js_operators.asp and www.w3schools.com/js/js_comparisons.asp.

eval

eval takes a string argument and interprets it as JavaScript code.

1
2
3
"use strict";

console.log(eval('if (5 < 7) true; else false;'));
For security and performance reasons usage of eval should be avoided (see developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval).

4.3.11. Conditional statements

if

Oftentimes the behavior of our program depends on a condition. For example, if we have developed a social network and we want to congratulate the user on his birthday, we first need to verify the condition of the user’s birthday being true. Let’s look at a couple of examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
"use strict";

// We ask the user a very tough question and store his answer.
const correctAnswer = 7;
const userAnswer = parseInt(prompt('3 + 4 = '));
// Now we check whether his answer is correct or not and react accordingly.
if (userAnswer === correctAnswer) document.body.innerHTML += 'Well done!<br>';
else document.body.innerHTML += 'Please check your answer.<br>';

/* Let's assume the user's birthday is 1.2.1983.
 First we need to get the current date.
 Then we need to check whether day and month correspond
 to the user's birthday.
 If that's the case, then we will congratulate him, otherwise
 we'll tell him how far away his birthday is.
 */
// getMonth() returns a number between 0 and 11, so we need to subtract 1!
const userMonth = 1; // February, January would be 0.
const userDay = 1; // User's month and day of birth.
const date = new Date(); // Get the current date.
if (date.getMonth() === userMonth && date.getDate() === userDay)
  alert('Happy birthday!');
/* The else part is optional. In this case we don't need it, as we only want
 to do something if the condition is true.
 */

// Now we create a little script that displays the name of the current month.
const month = date.getMonth(); // We reuse the date variable created above.
if (month === 0) document.body.innerHTML += 'January<br>';
else if (month === 1) document.body.innerHTML += 'February<br>';
else if (month === 2) document.body.innerHTML += 'March<br>';
else if (month === 3) document.body.innerHTML += 'April<br>';
else if (month === 4) document.body.innerHTML += 'May<br>';
else if (month === 5) document.body.innerHTML += 'June<br>';
else if (month === 6) document.body.innerHTML += 'July<br>';
else if (month === 7) document.body.innerHTML += 'August<br>';
else if (month === 8) document.body.innerHTML += 'September<br>';
else if (month === 9) document.body.innerHTML += 'October<br>';
else if (month === 10) document.body.innerHTML += 'November<br>';
else if (month === 11) document.body.innerHTML += 'December<br>';
switch

Another instruction that can be used if there are many alternatives to choose from is switch. A detailed explanation can be found at www.w3schools.com/js/js_switch.asp. Here’s is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
"use strict";

const date = new Date(); // Get the current date.
const month = date.getMonth(); // We reuse the date variable created above.
switch (month) {
  case 0:
    document.body.innerHTML += 'January<br>';
    break;
  /* If we leave this out, the following instructions will be executed,
   even though month is 0 and not 1.
   */
  case 1:
    document.body.innerHTML += 'February<br>';
    break;
  case 2:
    document.body.innerHTML += 'March<br>';
    break;
  case 3:
    document.body.innerHTML += 'April<br>';
    break;
  case 4:
    document.body.innerHTML += 'May<br>';
    break;
  case 5:
    document.body.innerHTML += 'June<br>';
    break;
  case 6:
    document.body.innerHTML += 'July<br>';
    break;
  case 7:
    document.body.innerHTML += 'August<br>';
    break;
  case 8:
    document.body.innerHTML += 'September<br>';
    break;
  case 9:
    document.body.innerHTML += 'October<br>';
    break;
  case 10:
    document.body.innerHTML += 'November<br>';
    break;
  case 11:
    document.body.innerHTML += 'December<br>';
    break;
  default:
    document.body.innerHTML += 'Invalid month!<br>';
}

4.3.12. Loops

Loops are used to execute a block of, i.e. one or several, statements, several times. JavaScript provides the for, while, for in and do while loops. Each loop consists of a head and a body part.

for

The for loop head specifies the start value, a condition and what should be done after each iteration of the body. This type of loop is the preferred choice if we know the number of iterations in advance. We already saw an example in Numbers. Let’s study a couple more examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
"use strict";

// A very basic loop.
for (var i = 0; i < 4; i++) {
  // Variable i is defined for the whole function, in this case the whole script as there
  // is no function.
  document.body.innerHTML += `i: ${i}<br>`;
}

/*
 Let's calculate the sum of all numbers between a and b, except those that
 can be divided by 5.
 */
let a = 2, b = 123, sum = 0;
for (i = a; i <= b; i++) { // i was defined using var -> function scope
  if (i % 5 !== 0) {
    sum += i;
  }
}
console.log('sum: ' + sum);

console.log('Here is an illustration of what block scope means.');
// A very basic loop.
for (let j = 0; j < 4; j++) { // Variable j is only defined for this block.
  document.body.innerHTML += `i: ${i}<br>`;
}

/*
 Let's calculate the sum of all numbers between a and b, except those that
 can be divided by 5.
 */
sum = 0;
for (j = a; j <= b; j++) { // j was defined using let -> block scope
                           // To solve this we would have to define j for this block using let j = a;
  if (j % 5 !== 0) {
    sum += j;
  }
}
console.log(`sum: ${sum}`);
while

The while loop head only specifies the condition that needs to be true for the loop body to be executed. The condition can be any boolean expression, i.e. we do not necessarily need a counter variable. Let’s look at an example:

1
2
3
4
5
6
7
8
9
10
11
12
"use strict";

const result = 2 + 2;
let input, count = 1; // Define variables.
/* As long as the user does not enter the correct answer, we loop.
 Given that prompt returns a string, we need to convert it to an integer.
 */
while ((input = parseInt(prompt('2 + 2 = '))) !== result) {
  document.body.innerHTML += 'Wrong answer, please try again.<br>';
  count++; // Increase the attempt counter.
}
console.log(`Correct, it took you ${count} attempt(s).`);
for in

for in loops through the enumerable properties of an object and includes the enumerable properties of the prototype chain (cf. Objects and classes).

1
2
3
4
5
6
7
8
9
10
11
"use strict";

const car = {
  color: 'black',
  weight: 1500,
  length: 4.5
};

for (const prop in car) {
  console.log(`Property name: ${prop} property value: ${car[prop]}`);
}

You should not use for in to loop through an array, as the following example inspired by "Effective JavaScript" p. 132 shows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"use strict";

const grades = [23, 45, 56, 43, 32, 29];
let total = 0;
for (const grade in grades) {
  total += grade;
}
let average = total / grades.length;
console.log(`Average: ${average}`); // 2057.5 -> wrong, but why?

// Let's add a debugging instruction to our loop, so that we can see what happens:
total = 0;
for (const grade in grades) {
  total += grade;
  console.log(`${grade} ${total}`);
}

// Now we see that for in loops through the KEYS of the array, not the VALUES.
// The correct approach is to use a for loop:
total = 0;
for (let i = 0; i < grades.length; i++) {
  total += grades[i];
  console.log(`${grades[i]} ${total}`);
}
average = total / grades.length;
console.log(`Average: ${average}`); // 38 -> correct
do while

This is identical to the while loop, except that the body of do while is always executed at least once, as the condition is only checked after the execution instead of before.

4.3.13. Jumps and exceptions

Jump statements instruct the JavaScript interpreter to jump to a different source code location.

Labeled statements

A JavaScript statement can be labeled by writing the label followed by a colon.

break

Used alone, break causes the innermost enclosing loop or switch statement to exit immediately. If followed by a label, it terminates the enclosing statement that has the specified label. Take a close look at these examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
"use strict";

const matrix = [
  [1, 3, 5, 7, 9], // sum 25
  [2, 2, 'a', 2, 2], // sum 8
  [3, 4, 5, 6, 7], // sum 25
  [9, 8, 7, 6, 5], // sum 35
  [4, 4, 4, 4, 4] // 20
];
let sum = 0, error = false;
outerloop: for (let i = 0; i < matrix.length; i++)
  for (let j = 0; j < matrix[0].length; j++) {
    if (isNaN(matrix[i][j])) {
      error = true;
      break outerloop;
    }
    sum += matrix[i][j];
  }
console.log(`Sum: ${sum} error: ${error}`);

sum = 0;
error = false;
for (let i = 0; i < matrix.length; i++)
  for (let j = 0; j < matrix[0].length; j++) {
    if (typeof matrix[i][j] !== 'number') {
      error = true;
      break;
    }
    sum += matrix[i][j];
  }
console.log(`Sum: ${sum} error: ${error}`);
continue

continue is similar to break, except that it does not exit the loop but restarts it at the next iteration, i.e. it terminates only the current iteration, not the whole loop. Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"use strict";

const matrix = [
  [1, 3, 5, 7, 9], // sum 25
  [2, 2, 'a', 2, 2], // sum 8
  [3, 4, 5, 6, 7], // sum 25
  [9, 8, 7, 6, 5], // sum 35
  [4, 4, 4, 4, 4] // 20
];
let sum = 0, error = false;
outerloop: for (let i = 0; i < matrix.length; i++)
  for (let j = 0; j < matrix[0].length; j++) {
    if (typeof matrix[i][j] !== 'number') {
      error = true;
      continue outerloop;
    }
    sum += matrix[i][j];
  }
console.log(`Sum: ${sum} error: ${error}`);
Exception handling

Often our programs rely on the user to provide reasonable input. But what happens if the user provides invalid input? For instance, we have a function that calculates the product of all given parameters, assuming they are all numbers. If one of the parameters is a string, our script might not perform as expected. That’s not very professional and chances are, our users won’t like it. A better way is to throw an exception using the throw instruction and catch it using try catch finally. In the try block we put the code that is at risk of breaking, for instance on wrong user input. In the catch block we put the code that should be executed if something went wrong in the try block, i.e. an exception occurred. The finally block is optional and will always be executed as the final block. JavaScript has a built-in Error object (cf. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error), that serves to signal an error. Let’s study an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"use strict";

const product = () => {
  let prod = 1;
  for (let i = 0; i < arguments.length; i++) {
    if (typeof arguments[i] !== 'number')
      throw new Error('All arguments must be numbers!');
    prod *= arguments[i];
  }
  return prod;
};

try {
  console.log(product(2, 34, 5)); // OK
  console.log(product(2, 'abc', 5)); // Wrong arg -> trouble.
}
catch (error) {
  console.error(error);
}
finally {
  console.log('Job done');
}

4.3.14. Functions

A function is a block of code that is executed by "calling" the function. Functions are of fundamental importance in software development, as they permit to reuse code, i.e. we solve a problem once and can then use the solution as often as we want without having to reinvent the wheel.

Normal functions

A function is defined using the function keyword, followed by parentheses (), followed by curly brackets {}. A function can take one or several parameters, which represent information that is given to the function by the caller.

Parameters of primitive types are passed by value, whereas objects are passed by reference.

Within the curly brackets we find the body of the function, i.e. the code that is executed when the function is called. A function can return an object using the return keyword. Please note that return does 2 things:

  • Returns the given object, or nothing if no object is provided.

  • Terminates the function. This means that any instructions following return will not be executed.

Normal functions have a built-in arguments object, which contains an array of the arguments used when the function was called.

Also note that a normal function can be called before its declaration. This is called hoisting.

Let’s study a couple of examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
"use strict";

// A simple sum function
function sum(a, b) {
  return a + b;
}
const alpha = 34, beta = 67.89;
console.log(`The sum of ${alpha} and ${beta} is ${sum(alpha, beta)}.`);

/* We define a function without parameters that adds a paragraph and returns
 nothing.
 */
function sayHelloWorld() {
  const r = Math.floor(Math.random() * 256); // Generate random red component.
  const g = Math.floor(Math.random() * 256); // Random green component.
  const b = Math.floor(Math.random() * 256); // Random blue component.
  const p = document.createElement('p'); // Create new <p> element.
  p.style.color = 'blue'; // Set text and background colors.
  p.style.backgroundColor = 'rgb(' + r + ', ' + g + ', ' + b + ')';
  p.innerHTML = 'Hello world!'; // Set content.
  const main = document.querySelector('main'); // Get main element.
  main.appendChild(p); // Append the new <p> element to <main>.
}

// Now we call the function, i.e. we reuse the code to display the text 5 times.
for (let i = 1; i <= 5; i++) sayHelloWorld();

// Here we call the factorial function even before it's defined -> hoisting.
console.log(`The factorial of 7 is ${factorial(7)}.`);

/* The factorial function takes one parameter, a positive integer, and returns
 the number's factorial. Remember the formula: n! = n * (n - 1) * ... * 2.
 */
function factorial(x) {
  // If x is not a number, we return false.
  if (isNaN(x)) return false;
  x = x.toFixed(0); // Make sure x is an integer.
  let fact = 1; // In this variable we store the current result.
  for (let i = x; i >= 2; i--) fact *= i; // Loop to calculate factorial.
  return fact; // Return the result.
}

/* We can also define a function that works with a variable number of
 parameters, a so called variadic function.
 */
function printArgs() {
  for (let i = 0; i < arguments.length; i++)
    console.log(`Argument ${i}: ${arguments[i]} of type ${typeof arguments[i]}`);
  console.dir(arguments);
}

printArgs('Hi', 5.6, 5, false);

// Optional named parameters
// cf. http://exploringjs.com/es6/ch_core-features.html#sec_param-defaults-core-feature
function printFromTo(values, {start=0, end=-1, step=1} = {}) {
  console.log(`Start: ${start}`);
  console.log(`Step: ${step}`);

  if (step === 0)
    console.dir(new Error('Infinite loops are not a good idea...'));
  else for (let i = start; i < end; i += step) console.log(values[i]);
}

printFromTo([1,2,3,4,5,6]);
printFromTo([1,2,3,4,5,6], {start: 1, end: 6, step: 0});
printFromTo([1,2,3,4,5,6], {start: 1, end: 6, step: 2});
Arrow functions
An arrow function expression has a shorter syntax than a function expression and does not bind its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.

An arrow function is created using . It means that the value in the parentheses, if any, is passed as parameter to the block of code that the arrow is pointing to. An arrow function is defined like a variable.

Contrary to normal functions, which are read at compile-time, arrow functions are read at run-time. Therefore they must be defined in the code before they can be called.

Also contrary to a function, an arrow function does not have an arguments object (cf. point 18.a in www.ecma-international.org/ecma-262/6.0/#sec-functiondeclarationinstantiation). Instead we can use so called rest parameters using the …​ operator, which can also be used with normal functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
"use strict";

// A simple sum function
const sum = (a, b) => a + b;

const a = 34, b = 67.89;
console.log(`The sum of ${a} and ${b} is ${sum(a, b)}.`);

/* We define a function without parameters that adds a paragraph and returns
 nothing.
 */
const sayHelloWorld = () => {
  const r = Math.floor(Math.random() * 256); // Generate random red component.
  const g = Math.floor(Math.random() * 256); // Random green component.
  const b = Math.floor(Math.random() * 256); // Random blue component.
  const p = document.createElement('p'); // Create new <p> element.
  p.style.color = 'blue'; // Set text and background colors.
  p.style.backgroundColor = 'rgb(' + r + ', ' + g + ', ' + b + ')';
  p.innerHTML = 'Hello world!'; // Set content.
  const main = document.querySelector('main'); // Get main element.
  main.appendChild(p); // Append the new <p> element to <main>.
};

// Now we call the function, i.e. we reuse the code to display the text 5 times.
for (let i = 1; i <= 5; i++) sayHelloWorld();

/* The factorial function takes one parameter, a positive integer, and returns
 the number's factorial. Remember the formula: n! = n * (n - 1) * ... * 2.
 */
const factorial = x => {
  // If x is not a number, we return false.
  if (typeof x !== 'number') return false;
  x = x.toFixed(0); // Make sure x is an integer.
  let fact = 1; // In this variable we store the current result.
  for (let i = x; i >= 2; i--) fact *= i; // Loop to calculate factorial.
  return fact; // Return the result.
};

// A function expression can only be called after its definition.
console.log('The factorial of 7 is ' + factorial(7) + '.');

const printArgs = (...args) => {
  for (let i = 0; i < args.length; i++)
    console.log(`Argument ${i}: ${args[i]} of type ${typeof args[i]}`);
  console.dir(args);
};

printArgs('Hi', 5.6, 5, false);

const printFromTo = (values, {start=0, end=-1, step=1} = {}) => {
  if (step === 0)
    console.dir(new Error('Infinite loops are not a good idea...'));
  else for (let i = start; i < end; i += step) console.log(values[i]);
};

printFromTo([1,2,3,4,5,6]);
printFromTo([1,2,3,4,5,6], {start: 1, end: 6, step: 0});
printFromTo([1,2,3,4,5,6], {start: 1, end: 6, step: 2});

A major difference between a normal function and an arrow function is that in the case of a normal function, the scope is local whereas in the case of an arrow function, the scope is the surrounding code.

Use non-arrow functions for methods that will be called using the object.method() syntax. Those are the functions that will receive a meaningful this value from their caller. Use arrow functions for everything else.

The following example illustrates this difference (cf. this):

1
2
3
4
5
6
7
8
9
10
"use strict";

function localScope() {
  console.dir(this);
}

let globalScope = () => console.dir(this);

localScope();
globalScope();

For a more in-depth illustration of why this is very important, study stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback.

Variable scope

It is important to understand the concept of variable scope. A local variable, i.e. a variable that is declared inside the body of a function using the let or var keyword is called a local variable and only exists within the function body. A variable declared outside a function (with or without let or var) or a variable implicitly declared without let or var inside a function is a global variable, i.e. it exists even after the function execution has finished. Furthermore, if a global variable x is declared and inside a function we declare a local variable x, the local x will hide the global x, meaning that when we use x in the function, it will be the local and not the global one.

If you declare a variable without the var or let keyword, it will always be global, even if declared within a function! This can lead to errors that are hard to detect and should be avoided.

Let’s illustrate this with a few examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
"use strict";

let x = 7; // Declare and initialize a global variable.

f1(4); // We can call the normal function before it is defined -> function hoisting.
console.log('x: ' + x); // x is the GLOBAL variable.

function f1(a) {
  let x = a / 2;
  console.log(`x: ${x}`); // x is the LOCAL variable.
  // The global variable x is not usable here.
}

let f2 = () => {
  x++; // We modify the global variable x, which is a very bad idea.
}

console.log(`x: ${x}`); // x is the GLOBAL variable.
f2();
console.log(`x: ${x}`); // x is the GLOBAL variable.

let f3 = () => {
  let x = 23;
  console.log(`x: ${x}`); // x is the LOCAL variable.
}

f3();
// x is GLOBAL, the local one from f3 does not exist outside of f3.
console.log(`x: ${x}`);

Note in the examples above that we called normal function f1 before its declaration. This behavior is possible because of function hoisting, i.e. a normal function is read at run-time, as mentioned above.

let vs var

This first example does not work as expected:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Lexical scoping 1</title>
    <meta charset=utf-8>
    <script>
      'use strict';

      const init = () => {
        const buttons = document.querySelectorAll('button');
        for (var i = 0; i < buttons.length; i++) {
          buttons[i].addEventListener('click', () => {
            console.log(`Button ${i + 1} clicked`);
          });
        }
      };

      addEventListener('load', init);
    </script>
  </head>
  <body>
    <main>
      <button>B1</button>
      <button>B2</button>
      <button>B3</button>
    </main>
  </body>
</html>

The reason is that the scope of var is the entire enclosing function, so the value that will be used in the event handler is the last value of i, which is 3 in this case.

The second example solves this problem using let.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Lexical scoping 2</title>
    <meta charset=utf-8>
    <script>
      'use strict';

      const init = () => {
        const buttons = document.querySelectorAll('button');
        for (let i = 0; i < 3; i++) {
          buttons[i].addEventListener('click', () => {
            console.log(`Button ${i + 1} clicked`);
          });
        }
      };

      addEventListener('load', init);
    </script>
  </head>
  <body>
    <main>
      <button>B1</button>
      <button>B2</button>
      <button>B3</button>
    </main>
  </body>
</html>

let has block scope, which means that the value used in the event handler is the value of i at that point and time in the block, as one would intuitively expect.

Anonymous functions

We can pass a nameless function as a parameter to a function or assign it to a variable. This will be particularly useful when we deal with event handlers as we’ll see later on.

Here is an example of an anonymous function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
"use strict";

// This function takes as parameter a function and a number.
function f1(f, x) {
  // We call the function x times, each time passing i as parameter.
  for (let i = 0; i < x; i++) f(i);
}

// We call f1 with an anonymous function and a number as parameters.
f1(function (x) {
  console.log(x);
}, 5);

// The same using an anonymous function expression.
f1(x => {
  console.log(x);
}, 5);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>x1</title>
    <meta charset=UTF-8>
  </head>
  <body>
  <script>
    'use strict';

    const init = () => {
      let i = 7;
      setInterval(() => {
        console.log(i--);
      }, 500);
    };

    addEventListener('load', init);
  </script>
  </body>
</html>
Asynchronous programming
Promises
A Promise is an object representing the eventual completion or failure of an asynchronous operation.

developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

hackernoon.com/transforming-callbacks-into-promises-and-back-again-e274c7cf7293

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
'use strict';

const httpGET = URL => {
  return new Promise((resolve, reject) => {
    const req = new XMLHttpRequest();
    req.addEventListener('load', e => {
      resolve(e.target.response);
    });
    req.addEventListener('error', e => {
      reject(new Error(e.target.statusText));
    });
    req.open('GET', URL);
    req.send();
  });
};

console.log('x1');
httpGET('https://students.btsi.lu').then(res => {
    console.log(`Contents: ${res}`);
  },
  err => {
    console.log(`Something went wrong: ${err}`);
  }
);
console.log('x2');

const myfun4 = (x, resolve, reject) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (x > 5) resolve('All good');
      else reject('Not good');
    }, 2000);
  });
};
async and await
Async/await makes asynchronous code look and behave a little more like synchronous code. This is where all its power lies.
Remember, the await keyword is only valid inside async functions. If you use it outside of an async function’s body, you will get a SyntaxError.

hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9

exploringjs.com/es2016-es2017/ch_async-functions.html

developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

ponyfoo.com/articles/understanding-javascript-async-await

tc39.github.io/ecmascript-asyncawait

stackoverflow.com/questions/42964102/syntax-for-async-arrow-function

medium.com/front-end-hacking/async-await-is-not-about-making-asynchronous-code-synchronous-ba5937a0c11e

exploringjs.com/es2016-es2017/ch_async-functions.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
'use strict';

const httpGET = URL => {
  return new Promise((resolve, reject) => {
    const req = new XMLHttpRequest();
    req.addEventListener('load', e => {
      resolve(e.target.response);
    });
    req.addEventListener('error', e => {
      reject(new Error(e.target.statusText));
    });
    req.open('GET', URL);
    req.send();
  });
};

(async () => {
  console.log('x1');
  await httpGET('https://students.btsi.lu').then(res => {
      console.log(`Contents: ${res}`);
    },
    err => {
      console.log(`Something went wrong: ${err}`);
    }
  );
  console.log('x2');
})();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
'use strict';

const resolveAfter2Seconds = x => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const rand = Math.random();
      rand < 0.5 ? resolve(x) : reject(x);
    }, 2000);
  });
}

(async () => {
  try {
    console.log('x1');
    console.log(await resolveAfter2Seconds(10));
    console.log(await resolveAfter2Seconds(15));
    console.log('x2');
  } catch (e) {
    console.error(e);
  }
})();

4.3.15. Debugging

Debugging is a methodical process of finding and reducing the number of bugs, or defects, in a computer program.

The short video at youtu.be/0zWiq8FB3Xg shows how this works in practice using the following HTML document:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!DOCTYPE html>
<html lang=en>
  <head>
    <title>Debugging example</title>
    <meta charset=utf-8>
  </head>
  <body>
    <main>
      <script>
        "use strict";

        function f1() {
          // A very basic loop.
          for (let i = 0; i < 4; i++) {
            document.write('i: ' + i + '<br>');
          }
        }

        function f2() {
          // A very basic loop.
          for (var i = 0; i > 4; i++) {
            document.write('i: ' + i + '<br>');
          }
        }

        f1();
        f2();
      </script>
    </main>
  </body>
</html>

4.3.16. Arrays

Arrays are ordered value collections. Each value or element has its position, which is called index. The index of the first element is 0 and the position of the last element is the length of the array minus 1. The index is a 32 bit number, so the maximum number of elements in an array is 2^32 - 1. Arrays are dynamic and we do not have to specify any initial size.

Creating and iterating

We create an array either as an array literal, which is the recommended way, or using the Array constructor. The latter method is conducive to errors, as explained in the example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
"use strict";

const a1 = []; // Create an empty array.
const a2 = [1, 4, 2, 5, 3]; // Create an array with 5 numbers.
const a3 = ['Donald', 45, false]; // Create an array with 3 elements of different types.
console.log(`Length of a1: ${a1.length}`);
console.log(`Length of a2: ${a2.length}`);
console.log(`Length of a3: ${a3.length}`);
console.log('Elements of a1:');
for (let i = 0; i < a1.length; i++) console.log(a1[i]);
console.log('Elements of a2:');
/* This is a dangerous way of looping through an array, as all enumerable properties
 of the array and its prototype object will be returned and the order is not guaranteed
 by the ECMAScript specification.
 */
for (let i in a2) console.log(a2[i]);
console.log('Elements of a3:');
/* If the order of the returned elements is not important, we can use the in operator by
 adding a test to exclude inherited enumerable properties.
 */
Object.getPrototypeOf(a3).x=7;
for (let i in a3) {
  //if (!a3.hasOwnProperty(i)) continue;
  console.log(a3[i]);
}

console.log('Elements of a3:');
// The most concise method is for of
for (const elem of a3) console.log(elem);

const a4 = new Array(); // Create an empty array.
/* You need to be careful when creating arrays with new. If there is only one parameter, it
 indicates the number of elements. If there are several parameters, these will be the
 elements of the array. This adds unneeded complexity and encourages errors.
 */
const a5 = new Array(8); // Create an array with no elements and length 8.
// Create an array with 3 elements of different types.
const a6 = new Array('Donald', 'Duck', 45, true);
console.log(`Length of a4: ${a4.length}`);
console.log(`Length of a5: ${a5.length}`);
console.log(`Length of a6: ${a6.length}`);
console.log('Elements of a4:');
for (const elem of a4) console.log(elem);
console.log('Elements of a5 using a normal for:');
for (let i = 0; i < a5.length; i++) console.log(a5[i]);
// Note the different behavior: for/in simply skips undefined elements.
console.log('Elements of a5 using for/in:');
for (let i in a5) console.log(a5[i]);
console.log('Elements of a6:');
for (const elem of a6) console.log(elem);
To know whether an array contains a specific element use Array.includes().

It is important to note that arrays are objects. Therefore the in operator will use all enumerable properties of the object itself and its prototype, as described in Testing properties. This will include methods that have been added to the prototype unless they are not enumerable. Furthermore, the ECMAScript specification does not fix the order in which the in operator returns elements. If element order is important, we should use a standard for loop to iterate through an array. If order does not matter, but we cannot guarantee that the array prototype is not polluted with enumerable properties, we should include a test to filter these, as shown in the examples above.

The preferred and most concise method to iterate over arrays is for of.
Adding and deleting
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"use strict";

const a = [];
a[5] = 'Donald';
/* The array has only one element, at index 5, but the length of the array is 6!
   This is called a sparse array. */
console.log(`Contents of array a: ${a} length: ${a.length}`);
a[1] = false;
console.log(`Contents of array a: ${a} length: ${a.length}`);
a.push('Duck'); // Add an element at the end.
console.log(`Contents of array a: ${a} length: ${a.length}`);
a[a.length] = 23e4; // Another way of adding an element at the end.
console.log(`Contents of array a: ${a} length: ${a.length}`);
delete a[a.length-1]; // Delete the last element. This does not alter the array length!
console.log(`Contents of array a: ${a} length: ${a.length}`);
a.pop(); // Remove the last element and return it. This does adjust the length.
console.log(`Contents of array a: ${a} length: ${a.length}`);
console.log('Just removed ' + a.pop());
console.log(`Contents of array a: ${a} length: ${a.length}`);
Multidimensional arrays

An array element can be another array. So we can easily create multidimensional arrays like so: students.btsi.lu/evegi144/WAD/JS/array_multidim.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
"use strict";

const init = () => {
  const MATRIXLENGTH = 10; // 10 by 10
// Create an empty 10 x 10 matrix.
  const matrix = new Array(MATRIXLENGTH);
  for (let i = 0; i < MATRIXLENGTH; i++) matrix[i] = new Array(MATRIXLENGTH);
// Fill the matrix with random integers from [0, 99].
  for (let i = 0; i < MATRIXLENGTH; i++)
    for (let j = 0; j < MATRIXLENGTH; j++) matrix[i][j] = Math.floor(100 * Math.random());
// Display the matrix as a table.
  let table = '<table><caption>Random matrix</caption>';
  for (let i = 0; i < MATRIXLENGTH; i++) {
    table += '<tr>';
    for (let j = 0; j < MATRIXLENGTH; j++)
      table += `<td>${matrix[i][j]}</td>`;
    table += '</tr>';
  }
  document.body.innerHTML += `${table}</table>`;
};

addEventListener('load', init);
Methods

We have already seen includes, push and pop methods. A complete reference with examples can be found at www.w3schools.com/jsref/jsref_obj_array.asp.

Turning arrays into parameters

Using the spread operator …​ we can turn arrays into parameters. Why would we want to do this? Let’s assume for instance, we want to determine the highest value in an array of numbers. Math.max() does not work on arrays. Using the spread operator, this is no problem: students.btsi.lu/evegi144/WAD/JS/array_spread.html

1
2
3
4
5
"use strict";

const arr = [];
for (let i = 0; i < 100; i++) arr.push(Math.random());
console.log(`The biggest number is ${Math.max(...arr)}`);

4.3.17. Template literals

A template literal is a new kind of string literal that can span multiple lines and interpolate expressions (include their results).
1
2
3
4
5
'use strict';

const firstName = prompt('Please enter your first name');
const lastName = prompt('Please enter your last name');
alert(`Hello ${firstName} ${lastName}, how are you?`);
The literal itself is delimited by backticks (`), the interpolated expressions inside the literal are delimited by ${ and }. Template literals always produce strings.

There’s much more to template literals, for the details please check the link above.

4.3.18. Objects and classes

In JavaScript, anything that is not a string, number, boolean, null or undefined is an object. Objects are collections of properties (cf. www.ecma-international.org/ecma-262/#sec-object-type). They allow us to regroup data and functions that belong together under one name and to reuse them. One purpose is the representation of real world objects. A good introduction can be found at developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects.

JS comes with a number of standard built-in objects, details of which can be found at developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects.

Prototypes
If you have traditional object-oriented programming experience, e.g. with C++ or Java, it is imperative to understand that JS is not class- but prototype-based. To get a good understanding of what the difference is and why it matters study You Don’t Know JS.

Most objects are derived from another object. This other object is called prototype in JavaScript. Object is the basic object in JavaScript from which normally all other objects inherit, directly or indirectly. To determine the prototype of an object, we use Object.getPrototypeOf(), where we pass the object as parameter.

Object creation

There are three ways to create objects.

as literals

From "JavaScript The Definitive Guide" p. 117: "An object literal is a comma-separated list of colon-separated name:value pairs, enclosed within curly braces." this refers to the object itself, whose property we want to use. Object literals are often used to avoid declaring a large number of global variables and functions by creating a namespace. This helps to document that a set of properties belong together and serve a common purpose. When we create an object literal, its prototype is Object.prototype. WMOTU Invaders object-oriented provides a sample application.

Examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
"use strict";

const myMerc = {
  brand: 'Mercedes',
  price: 100000,
  addVAT() {
    this.price = Math.ceil(this.price * 1.15);
  }
};
const myBMW = {
  brand: 'BMW',
  price: 60000,
  addVAT() {
    this.price = Math.ceil(this.price * 1.15);
  }
};

document.body.innerHTML += `Mercedes price without VAT: ${myMerc.price.toLocaleString()}<br>`;
myMerc.addVAT();
document.body.innerHTML += `Mercedes price with VAT: ${myMerc.price.toLocaleString()}<br>`;
document.body.innerHTML += `BMW price without VAT: ${myBMW.price.toLocaleString()}<br>`;

const empty = {}; // We create an empty object the REFERENCE to which is saved in this
// constant.
// We save the REFERENCE to object empty in constant myDog. This means that empty and myDog
// point to the same object!
const myDog = empty;
myDog.name = 'Idefix'; // We give the myDog, which is the same as the empty, object a name
myDog.bark = () => { // and a function.
  document.body.innerHTML += 'Wouf wouf!<br>';
};

document.body.innerHTML += `myDog's name is ${myDog.name}<br>`;
myDog.bark();
document.body.innerHTML += `Objects myDog and empty are identical: ${myDog === empty}<br>`;
document.body.innerHTML += `empty's name is ${empty.name}<br>`;
empty.bark();

const doggy = Object.create(myDog);
doggy.bark();
myDog.name = 'Toto';
document.body.innerHTML += `empty's name is ${empty.name}<br>`;
document.body.innerHTML += `myDog's name is ${myDog.name}<br>`;
document.body.innerHTML += `doggy's name is ${doggy.name}<br>`;
console.log('Prototype of empty: ');
console.dir(Object.getPrototypeOf(empty));
console.log('Prototype of myDog: ');
console.dir(Object.getPrototypeOf(myDog));
console.log('Prototype of doggy: ');
console.dir(Object.getPrototypeOf(doggy));
from a constructor with new

new must be followed by a constructor, which is a function that initializes the newly created object. As noted above, this refers to the object itself, whose property we want to use. The advantage of this approach compared to the previous one is that we can create as many objects as we like using the same constructor. When we use a constructor, the prototype is the prototype property of the constructor. Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
"use strict";

function Car(brand, price) {
  this.brand = brand;
  this.price = price;
  this.addVAT = function () {
    this.price = Math.ceil(this.price * 1.15);
  };
}

const myMerc = new Car('Mercedes', 100000), myBMW = new Car('BMW', 60000);

document.body.innerHTML += `Mercedes price without VAT: ${myMerc.price.toLocaleString()}<br>`;
myMerc.addVAT();
document.body.innerHTML += `Mercedes price with VAT: ${myMerc.price.toLocaleString()}<br>`;
document.body.innerHTML += `BMW price without VAT: ${myBMW.price.toLocaleString()}<br>`;
myMerc.price = 80000; // This only changes the price of myMerc, but not myBMW.
document.body.innerHTML += `Mercedes price without VAT: ${myMerc.price.toLocaleString()}<br>`;
document.body.innerHTML += `BMW price without VAT: ${myBMW.price.toLocaleString()}<br>`;
document.body.innerHTML += `Prototype of myMerc: ${Object.getPrototypeOf(myMerc)}<br>`;
console.log('Prototype of myMerc: ');
console.dir(Object.getPrototypeOf(myMerc));
document.body.innerHTML += `Prototype of myBMW: ${Object.getPrototypeOf(myBMW)}<br>`;
console.log('Prototype of myBMW: ');
console.dir(Object.getPrototypeOf(myBMW));

Or using the syntactic sugar introduced in ECMAScript 6: students.btsi.lu/evegi144/WAD/JS/objects_new2.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
"use strict";

class Car {
  constructor(brand, price) {
    this.brand = brand;
    this.price = price;
  }

  addVAT() {
    this.price = Math.ceil(this.price * 1.15);
  }
}

const myMerc = new Car('Mercedes', 100000), myBMW = new Car('BMW', 60000);

document.body.innerHTML += `Mercedes price without VAT: ${myMerc.price.toLocaleString()}<br>`;
myMerc.addVAT();
document.body.innerHTML += `Mercedes price with VAT: ${myMerc.price.toLocaleString()}<br>`;
document.body.innerHTML += `BMW price without VAT: ${myBMW.price.toLocaleString()}<br>`;
myMerc.price = 80000; // This only changes the price of myMerc, but not myBMW.
document.body.innerHTML += `Mercedes price without VAT: ${myMerc.price.toLocaleString()}<br>`;
document.body.innerHTML += `BMW price without VAT: ${myBMW.price.toLocaleString()}<br>`;
document.body.innerHTML += `Prototype of myMerc: ${Object.getPrototypeOf(myMerc)}<br>`;
console.log('Prototype of myMerc: ');
console.dir(Object.getPrototypeOf(myMerc));
document.body.innerHTML += `Prototype of myBMW: ${Object.getPrototypeOf(myBMW)}<br>`;
console.log('Prototype of myBMW: ');
console.dir(Object.getPrototypeOf(myBMW));
from a prototype with Object.create()

Almost all JavaScript objects inherit the properties of another object, their prototype. Object.create is a method that allows us to create a new object with a given prototype.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
"use strict";

const myMerc = Object.create({
  brand: 'Mercedes',
  price: 100000,
  addVAT() {
    this.price = Math.ceil(this.price * 1.15);
  }
});
const myBMW = Object.create({
  brand: 'BMW',
  price: 60000,
  addVAT() {
    this.price = Math.ceil(this.price * 1.15);
  }
});

const init = () => {
  document.body.innerHTML += `Mercedes price without VAT: ${myMerc.price.toLocaleString()}<br>`;
  myMerc.addVAT();
  document.body.innerHTML += `Mercedes price with VAT: ${myMerc.price.toLocaleString()}<br>`;
  document.body.innerHTML += `BMW price without VAT: ${myBMW.price.toLocaleString()}<br>`;
  myMerc.price = 80000; // This only changes the price of myMerc, but not myBMW.
  document.body.innerHTML += `Mercedes price without VAT: ${myMerc.price.toLocaleString()}<br>`;
  document.body.innerHTML += `BMW price without VAT: ${myBMW.price.toLocaleString()}<br>`;
  document.body.innerHTML += 'The prototype of myBMW has the following properties:<br>';
  for (let o in Object.getPrototypeOf(myBMW)) document.body.innerHTML += `${o}<br>`;
  document.body.innerHTML += `Prototype of myBMW: ${Object.getPrototypeOf(myBMW)}<br>`;
  console.log('Prototype of myBMW: ');
  console.dir(Object.getPrototypeOf(myBMW));
}

addEventListener('load', init);

It is important to understand the difference between a constructor and a prototype. The prototype of an object contains all the properties that are common to all objects that have this prototype. They exist only once in the browser memory. Thus any changes to any of these properties are automatically reflected in all the objects that inherit from this prototype! Take a close look at the following examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
"use strict";

const animal = {
  speciesName: '',
  sayHello() {
    document.write(`Hi, I am a ${this.speciesName}<br>`);
  }
};

// Object animal is the prototype of objects myDog and myCat.
const myDog = Object.create(animal), myCat = Object.create(animal);
animal.sayHello();
myDog.sayHello();
myCat.sayHello();
// If we change a property of the prototype, it will affect all objects with this prototype.
animal.speciesName = 'dog';
animal.sayHello();
myDog.sayHello();
myCat.sayHello();

// Now let's use constructors.
// Each object constructed with this constructor will have its own name and bark properties.
function Dog(name) {
  this.name = name;
  this.bark = () => {
    document.write(`${this.name} says wouf wouf!<br>`);
  };
}

function Cat(name) {
  this.name = name;
  this.miaow = function () {
    document.write(`${this.name} says mmmmiiiiaaaaoooowwww!<br>`);
  };
}

class Ape {
  constructor(name) {
    this.name = name;
  }

  scream() {
    document.write(`${this.name} screams Ouaaaaaaaahhhhhhhh!<br>`);
  }

  crackNut() {
    document.write(`${this.name} cracked a nut.<br>`);
  }
}

class Gorilla extends Ape {
  constructor(name) {
    super(name);
  }

  scream() {
    document.write(`${this.name} screams I am BOSS!!!<br>`);
  }
}

const Toto = new Gorilla('Toto');
Toto.scream();
Toto.crackNut();
Ape.prototype.crackNut = function() {
  document.write(`${this.name} smashed a nut.<br>`);
};
Toto.crackNut();

// Create 2 new dogs using the dog constructor.
let myDog1 = new Dog('Bello'), myDog2 = new Dog('Toro');
// Create 2 new cats using the cat constructor.
let myCat1 = new Cat('Kitty'), myCat2 = new Cat('Tiger');
myDog1.bark();
myDog2.bark();
myCat1.miaow();
myCat2.miaow();
myDog2.name = 'Idefix'; // Change a property of a dog object.
myDog1.bark(); // The change only affects the other dog object.
myDog2.bark();

// Now let's combine constructor and prototype.
// All dogs and cats will have the same species_name and sayHello properties
Dog.prototype = animal;
Cat.prototype = animal;
// Create 2 new dogs using the dog constructor.
myDog1 = new Dog('Bello');
myDog2 = new Dog('Toro');
// Create 2 new cats using the cat constructor.
myCat1 = new Cat('Kitty');
myCat2 = new Cat('Tiger');

// Assign prototype.
myDog1.sayHello();
myDog2.sayHello();
myCat1.sayHello();
myCat2.sayHello();
animal.speciesName = 'bird';
myDog1.sayHello();
myDog2.sayHello();
myCat1.sayHello();
myCat2.sayHello();
myDog1.bark();
myDog2.bark();
myCat1.miaow();
myCat2.miaow();
console.log('Prototype of myDog1:');
console.dir(Object.getPrototypeOf(myDog1));
console.log('Prototype of myDog2:');
console.dir(Object.getPrototypeOf(myDog2));
console.log('Prototype of myCat1:');
console.dir(Object.getPrototypeOf(myCat1));
console.log('Prototype of myCat2:');
console.dir(Object.getPrototypeOf(myCat2));
this

Mastery of the this keyword is a key requirement for understanding JS objects. You should therefore study the excellent explanation at developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this.

Getting and setting properties

To get or set properties of an object we can either use the dot (.) or the square bracket ([]) operators. There is an important difference between these two: when using the dot operator, the right-hand must be an identifier, i.e. the name of the property. This cannot be a programmatically generated dynamic value. When using the square bracket operator, the value between the brackets must be an expression that evaluates to a string or to something that can be converted to a string. This opens up endless possibilities, so let’s look at a few examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
"use strict";

// The [] operator allows us to use names with spaces as property names:
const company = {
  'chief executive officer': 'Donald Duck'
};

//document.innerHTML += `${company.chief executive officer}<br>`; // Does not work!
document.innerHTML += `${company['chief executive officer']}<br>`; // Works!


class Student {
  constructor(name) {
    this.name = name;
    this.branches = {};
    // If the function is already defined, no need to define it again. This check is optional.
    if (!Student.prototype.addBranch)
      Student.prototype.addBranch = (name, average) => {
        this.branches[name] = average;
      };
    // If the function is already defined, no need to define it again. This check is optional.
    if (!Student.prototype.getTotalAverage)
      Student.prototype.getTotalAverage = () => {
        let avg = 0, count = 0;
        for (let branch in this.branches) {
          avg += this.branches[branch];
          count++;
        }
        if (count) return avg / count;
        else return undefined;
      }
  }
}

const st1 = new Student('Bill'), st2 = new Student('Bob');
document.body.innerHTML += `${st1.name} average: ${st1.getTotalAverage()}<br>`;
st1.addBranch("INFOR", 49);
document.body.innerHTML += `${st1.name} average: ${st1.getTotalAverage()}<br>`;
st1.addBranch("MATHE", 34);
document.body.innerHTML += `${st1.name} average: ${st1.getTotalAverage()}<br>`;
st2.addBranch("INFOR", 57);
document.body.innerHTML += `${st2.name} average: ${st2.getTotalAverage()}<br>`;
st2.addBranch("MATHE", 44);
document.body.innerHTML += `${st2.name} average: ${st2.getTotalAverage()}<br>`;
Deleting properties

delete removes a property from an object. If you invoke delete on a prototype property, then all objects inheriting from this prototype lose this property.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
"use strict";

class Dog {
  constructor(name) {
    this.name = name;
    this.bark = () => {
      document.write(`${this.name} says wouf wouf!<br>`);
    };
  }
}

const myDog1 = new Dog('Bello');
myDog1.bark();
delete myDog1.name;
myDog1.bark();
const myDog2 = new Dog('Idefix');
myDog2.bark();
Testing properties

We have different options to test whether an object has a given property:

  1. The in operator requires the name of a property as a string on its left and an object on its right side. It returns true if the object has an enumerable own or inherited property by that name (cf. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in).

  2. Object.keys(obj) returns an array of a given object’s own enumerable properties (cf. https://developer.mozilla .org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys).

  3. Object.getOwnPropertyNames(obj) returns an array of all properties (enumerable or not) found directly upon a given object (cf. https://developer.mozilla .org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames).

  4. The hasOwnProperty() of an object checks whether the object has a property of the given name. It does not consider inherited properties for which it returns false (cf. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object /hasOwnProperty).

  5. propertyIsEnumerable() returns a Boolean indicating whether the specified property is enumerable (cf. https://developer.mozilla .org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable).

The following examples illustrate the different approaches:

1
2
3
4
5
6
7
8
9
10
11
"use strict";

const proto1 = {
  a: 'a',
  b: 'b'
};

const obj1 = Object.create(proto1);
for (const prop in obj1) console.dir(prop);
console.dir(Object.keys(obj1));
console.dir(Object.getOwnPropertyNames(obj1));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
"use strict";

class Dog {
  constructor(name) {
    this.name = name;
    this.bark = () => {
      document.write(`${this.name} says wouf wouf!<br>`);
    };
  }
}

const myDog1 = new Dog('Bello');
document.body.innerHTML += `toString is a property of myDog1: ${"toString" in myDog1}<br>`;

let keys = Object.keys(myDog1); // Get the enumerable own properties of the object.
let output = '';
for (let i = 0; i < keys.length; i++) // Display the property/value pairs.
  output += `${keys[i]}: ${myDog1[keys[i]]}<br>`;
document.body.innerHTML += `<p>${output}</p>`;

const s = [1, 2, 3, 4, 5]; // Create an array object.
keys = Object.keys(s); // Get the enumerable own properties of the object.
output = '';
for (let i = 0; i < keys.length; i++) // Display the property/value pairs.
  if (s.propertyIsEnumerable(keys[i])) output += `Enumerable ${keys[i]}: ${s[keys[i]]}<br>`;
document.body.innerHTML += `<p>${output}</p>`;

const props = Object.getOwnPropertyNames(s); // Get all own properties of the object.
output = '';
for (let i = 0; i < props.length; i++) {
  if (s.propertyIsEnumerable(props[i])) output += 'Enumerable ';
  output += `${props[i]}: ${s[props[i]]}<br>`;
}
document.body.innerHTML += `<p>${output}</p>`;
Object attributes

Every object has prototype, class and extensible attributes.

prototype

This attribute specifies the object’s parent, i.e. the object that it inherits from. As we’ve seen above, for object literals the prototype is Object.prototype, for objects created with new the prototype is the value of the constructor’s prototype property and for objects created with Object.create, the prototype is the first parameter passed to this method.

Every object has an isPrototypeOf method, which checks whether the object if the prototype of another object passed as parameter.

class

This internal read-only attribute tells us the type of the object. This attribute can take one of the following values: "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp" or "String".

extensible

This attribute determines whether new properties can be added to the object. Object.isExtensible() tells us whether an object is extensible or not. Object.preventExtensions allows us to make an object nonextensible.

Here is an example that illustrates the three object attributes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"use strict";

const animal = {
  species: 'animal',
  displaySpecies () {
    document.body.innerHTML += `I'm a ${this.species}<br>`;
  }
};
const dog = Object.create(animal);
document.body.innerHTML += `Animal is the prototype of dog: ${animal.isPrototypeOf(dog)}<br>`;
document.body.innerHTML += `The class of animal is: ${Object.prototype.toString.call(animal).slice(8, -1)}<br>`;
console.dir(Object.getPrototypeOf(animal));
document.body.innerHTML += `The class of dog is: ${Object.getPrototypeOf(dog).toString().slice(8, -1)}<br>`;
console.dir(Object.getPrototypeOf(dog));
document.body.innerHTML += `animal is extensible: ${Object.isExtensible(animal)}<br>`;
Object.preventExtensions(animal);
document.body.innerHTML += `animal is extensible: ${Object.isExtensible(animal)}<br>`;
document.body.innerHTML += `dog is extensible: ${Object.isExtensible(dog)}<br>`;
Property attributes

Each object property has, in addition to its value, the following three attributes:

  1. configurable: true if and only if the type of this property may be changed and if the property may be deleted from the corresponding object.

  2. enumerable

  3. writable.

Using Object.defineProperty(obj, prop, descriptor) we can set these attributes (cf. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object /defineProperty).

For a more in-depth treatment, see 2ality.com/2019/11/object-property-attributes.html.

Closures
A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created.

Study the MDN article, it explains the subject in detail with good examples. Then take a look at bonsaiden.github.io/JavaScript-Garden.

ECMAScript 6

ECMAScript 6 introduces more convenient syntax to work with objects and classes. Highly recommended introductions can be found at the following links:

scotch.io/tutorials/better-javascript-with-es6-pt-ii-a-deep-dive-into-classes

developer.mozilla.org/en-US/docs/Web/JavaScript/Ref