0000/00/00
00:00:000
00:00:00
0
X | Y
X | Y
0 | 0
0
0.0.0.0
XXX
user-agent
XX
—
—
We can visit the same website but see different things. Through personalization, individualization and customization your web-experience becomes as unique as your fingerprint. Websites constantly change their shape depending on the user: The layout transforms responsively when you open it on the phone, personal preferences are manifested in the light or dark mode, location-tracking and as user profiling tailors our feeds as well as the ads in it.
Filter bubbles, opaque feed algorithms and privacy concerns are one aspect of personalization on the Internet. Furthermore, what does personalization mean from a design and development point of view? What challenges does the responsive nature of the web pose for its design? How can the user’s influence on a website be made visible? Customization or personalization—what agency do we give the user?
We want to explore how we can design and develop websites that adapt to the user. What data can you collect from users to make a website more personal—and should you? Interactive user experiences allow for personal styles, conditional availabilities and different levels of authorship. The user can rewrite the narration depending on the links they click. Design variables can be made dependent on the user’s data, whether it is the mouse position or the time of day. We can even delegated our design decisions through customization options.
The course will consist of an introduction to the basics of HTML, CSS and JS, various inputs, coding sessions and consultations. Individually or in groups you will design and code small web experiments concerning different aspects of personalization. In the end we will published these experiments in form of a digital glossary. No coding skills are required. Students without prior programming experience are especially encouraged to attend and there will be different entry points for different experience levels.
Create at least one entry for the Personalized Web glossary.
A glossary entry consists of a term and its definition in the format of a website. Choose a term from the glossary list or pick your own word. There can be more than one entry for each term. Each entry is its own website, which will be linked from the glossary page.
An entry defines a term, by means of a text or an interaction concept. You can also question a term’s definition. Thus, each entry can be a reflection on the term but also your attitude towards it.
You decide how usable or unusable your website is. There’s room for errors, bugs and unfinished code.
Create at least one entry, but as many as you like. You can use one of the starter kits for different suggested words. Or you can start with a blank HTML boilerplate. Look for something in this assignment that is useful to you.
Fridays, from 10:00–15:00, as well as optional coding consultations from 15:30–17:30. The course takes place in presence, if possible.
14.10. | 21.10. | 28.10. | 04.11. | 11.11. | 18.11. | 25.11. | 02.12. | 16.12. | |
---|---|---|---|---|---|---|---|---|---|
10:00– 12:00 |
Introduction | Themes & Custom Styling → CSS |
Responsive Design → CSS |
Personal Process | Individualization & Interaction → JS |
kein Kurs | kein Kurs | Collective Coding |
|
13:00– 15:00 |
Individual Paths → HTML |
Collective Coding |
Collective Coding |
Glossary Design | kein Kurs | kein Kurs | Customization & Agency → JS |
Conclusion / Presentation | |
15:30– 17:30 |
Coding Consultations [optional] | Coding Consultations [optional] | Coding Consultations [optional] | Coding Consultations [optional] | Coding Consultations [optional] | Coding Consultations [optional] |
Welcome! Check out the course schedule, the about text and the assignment to get started.
<tag> content </tag>
<a href="http://link.com" target="_blank"> This is the hyperspace. </a>
“There’s a difference between choice and decision for. Choice is an option. Decision is a burden.”
Difference Between Choice and Decision – Techpinions“The upside of customization is that each user can get exactly what they want, because they are in control. The downside is that many users don’t know what they actually need and that most users are not interested in doing the work required to tweak the user interface to match their preferences.”
Customization vs. Personalization in the User Experience
div {
color: red;
}
<div id="subtitle" class="text"> Some content inside. </div>
* {
borders: 1px solid black;
}
div {
background-color: red;
}
“In 2019, 53% of the total web traffic came from mobile users.”
Mobile vs. Desktop Usage – Research.com
@media screen and (max-width: 800px) {
.element {
font-size: 18px;
}
}
when the browser is between 600px and 1200px wide (desktop):
@media screen and (min-width: 600px) and (max-width: 1200px){
.element {
font-size: 25px;
}
}
when the browser doesn’t support hove (mobile):
@media (hover: none){
.element:hover {
color: inherit;
}
}
:root {
--gapS: 5px;
--gapM: 10px;
--gapL: 20px;
--highlightColor: #0000FF;
}
.element{
color: var(--highlightColor);
margin: var(--gapS);
}
.element {
display: block;
}
.hidden {
display: none;
}
see also [Reference: Display & Visibility]
.element {
transform: translate(50%, 50%);
}
.element {
transform: translate(50%, 50%) rotateX(-12deg);
}
.element {
width: 200px;
transition: width 0.3s ease;
}
.element:hover {
width: 500px;
}
.element {
width: 200px;
color: red;
transition: width 0.3s, color 0.5s;
}
.element:hover {
width: 500px;
color: blue;
}
see also [Reference: CSS animations]
console.log('hi');
const message = 'hello';
console.log(message);
let counter = 1;
console.log(counter);
counter = counter + 1;
console.log(counter);
old JS: var
var message = 'hello';
console.log(message);
var counter = 1;
console.log(counter);
counter = counter + 1;
console.log(counter);
const number = 1;
const string = '1';
const boolean = false;
other data types in JS are e.g. undefined, null or objects
const logo = document.getElementById('logo');
const text = document.getElementsByClassName('text')[0];
const logo = document.getElementById('logo');
logo.style.backgroundColor = 'blue';
add / remove / toggle classes in JS:
const logo = document.getElementById('logo');
logo.classList.add('hidden');
change css-variable:
let root = document.documentElement;
root.style.setProperty('--highlightColor', 'red');
setTimeout(function(){
console.log('Finally here!');
}, 500);
const heading = document.getElementById('heading');
heading.innerHTML = 'New Heading';
const logo = document.getElementById('logo');
logo.addEventListener('click', function(){
console.log('the user clicked on the logo');
})
in HTML / JS:
<button onclick="myFunction()"> Click me! </button>
const circle = document.getElementById('circle');
document.body.addEventListener('mousemove', function(e){
const mouseX = e.clientX;
const mouseY = e.clientY;
console.log(mouseX, mouseY);
circle.style.top = mouseX + 'px';
circle.style.left = mouseY + 'px';
})
touchmove (mobile):
const circle = document.getElementById('circle');
document.body.addEventListener('touchmove', function(e){
const touch = e.touches[0];
const touchX = touch.clientX;
const touchY = touch.clientY;
console.log(touchX, touchY);
circle.style.top = touchX + 'px';
circle.style.left = touchY + 'px';
})
link mouse position to css-variable
const root = document.documentElement;
document.body.addEventListener("mousemove", e => {
root.style.setProperty('--mouse-x', e.clientX + 'px');
root.style.setProperty('--mouse-y', e.clientY + 'px');
});
“The upside of customization is that each user can get exactly what they want, because they are in control. The downside is that many users don’t know what they actually need and that most users are not interested in doing the work required to tweak the user interface to match their preferences.”
Customization vs. Personalization in the User Experience
function logHello() {
console.log('Hello World!');
}
logHello();
function with parameters:
function logSomething(params) {
console.log(params);
}
logSomething('Ciao World!');
const number = 5;
if(number < 5){
console.log('smaller than five');
} if else (number === 5) {
console.log('equals five');
} else {
console.log('higher than five or undefined');
}
[Reference: Comparison & Logical Operators]
const fruits = ['banana', 'apple', 'pear'];
console.log(fruits[0]);
const textElements = document.getElementsByClassName('text');
console.log(textElements[0]);
for (i = 0; i < 10; i++) {
// do something
}
const fruits = ['banana', 'apple', 'pear'];
for (i = 0; i < fruits.length; i++) {
const fruit = fruits[i];
console.log(i);
console.log(fruit);
}
const fruits = ['banana', 'apple', 'pear'];
for (const fruit of fruits) {
console.log(fruit);
}
const person = {
firstName: "Jane",
lastName: "Doe",
age: 25,
eyeColor: "brown"
};
console.log(person.firstName);
<div id="date">XX.XX.XXXX</div>
function displayOutput(type, data) {
const output = document.getElementById(type);
output.innerHTML = data;
}
displayOutput('date', '02.12.2022');
function updateOutput(type, dataFunction, rate) {
displayOutput(type, dataFunction());
setInterval(function () {
displayOutput(type, dataFunction());
}, rate);
}
updateOutput('time', getTime, 1000);
const timeOfPageLoad = new Date();
const year = timeOfPageLoad.getFullYear();
const month = timeOfPageLoad.getMonth() + 1;
const day = timeOfPageLoad.getDate();
const date = year + '/' + month + '/' + day;
displayOutput('date', date);
function getTime() {
const now = new Date();
let seconds = now.getSeconds();
let minutes = now.getMinutes();
let hours = now.getHours();
if (seconds < 10) {
seconds = '0' + seconds;
}
if (minutes < 10) {
minutes = '0' + minutes;
}
if (hours < 10) {
hours = '0' + hours;
}
const time = hours + ':' + minutes + ':' + seconds;
return time;
}
updateOutput('time', getTime, 1000);
function getTimePassed() {
const now = new Date();
const elapsedTime = new Date(now - timeOfPageLoad);
let seconds = elapsedTime.getSeconds();
let minutes = elapsedTime.getMinutes();
let hours = elapsedTime.getHours() - 1;
if (seconds < 10) {
seconds = '0' + seconds;
}
if (minutes < 10) {
minutes = '0' + minutes;
}
if (hours < 10) {
hours = '0' + hours;
}
const timePassed = hours + ':' + minutes + ':' + seconds;
return timePassed;
}
updateOutput('time-passed', getTimePassed, 1000);
let clicks = 0;
function displayClicks() {
clicks += 1;
displayOutput('clicks', clicks);
}
document.addEventListener('click', displayClicks);
let mouseX = 0;
let mouseY = 0;
function displayMousePosition(e) {
mouseX = e.clientX;
mouseY = e.clientY;
displayOutput('mouse', mouseX + '|' + mouseY);
}
document.addEventListener('mousemove', displayMousePosition);
let touchX = 0;
let touchY = 0;
function displayTouchPosition(e) {
touchX = e.touches[0].clientX;
touchY = e.touches[0].clientY;
displayOutput('touch', touchX + '|' + touchY);
}
document.addEventListener('touchmove', displayTouchPosition);
document.addEventListener('touchstart', displayTouchPosition);
function displayViewportSize() {
const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
displayOutput('viewport', vw + '|' + vh);
}
displayViewportSize();
window.addEventListener('resize', displayViewportSize);
const userAgent = window.navigator.userAgent;
displayOutput('user-agent', userAgent);
let scrollDistance = 0;
function displayScrollDistance(e) {
scrollDistance += e.deltaY;
displayOutput('scroll-distance', scrollDistance);
}
document.addEventListener('wheel', displayScrollDistance);
function fetchIpInformation() {
let apiKey = 'XXXXXXXXXXXXXX';
// make the request
fetch('https://api.ipgeolocation.io/ipgeo?apiKey=' + apiKey)
// extract JSON body content from HTTP response
.then(function (response) {
return response.json();
})
// output data
.then(function (data) {
const ipAddress = data.ip;
const country = data.country_code2;
const internetProvider = data.organization;
displayOutput('ip-address', ipAddress);
displayOutput('country', country);
displayOutput('internet-provider', internetProvider);
});
}
fetchIpInformation();
[via https://ipgeolocation.io]
<button id="getLocation"> GET LOCATION </button>
<div id="city"> XX </div>
<div id="weather"> XX </div>
function getLocation() {
displayOutput('city', 'loading...');
displayOutput('weather', 'loading...');
if (navigator.geolocation) {
window.navigator.geolocation.getCurrentPosition(getLocationAndFetchWeather);
} else {
x.innerHTML = 'Geolocation is not supported by this browser.';
}
}
function getLocationAndFetchWeather(position) {
// get location data
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
// fetch weather and city with location data
fetchWeatherAndCity(latitude, longitude);
}
// fetch weather
const apiKey = 'XXXXXXXXXXXXX';
function fetchWeatherAndCity(latitude, longitude) {
fetch(
`https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${latitude},${longitude}`,
{
headers: {
'Content-Type': 'application/json',
  },
}
)
.catch(function (error) {
console.log(error);
})
.then(function (response) {
return response.json();
})
.then(function (data) {
const city = data.location.name;
const weatherCondition = data.current.condition.text;
const weatherTemperature = data.current.temp_c;
const weatherPrecipitation = data.current.precip_mm;
const weatherOutput = weatherTemperature + '°C' + '|' + weatherCondition;
displayOutput('city', city);
displayOutput('weather', weatherOutput);
});
}
// add click listener to allow location button
const getLocationButton = document.getElementById('getLocation');
getLocationButton.addEventListener('click', getLocation);
[via https://www.weatherapi.com]
<link rel="stylesheet" href="css/style.css" </>
<link rel="stylesheet" href="./css/style.css" </>
from where the document is, go into the css folder
<link rel="stylesheet" href="../css/style.css" </>
from where the document is, go one folder back and go into the css folder
<link rel="stylesheet" href="/css/style.css" </>
from the root folder, go into the css folder