Welcome
You reached a self-hosted website with no ambition except being some kind of a notepad as well as a personal sandbox. But feel free to take away anything you may find useful.
I'm considering publishing here short articles about what I'm learning. I'll avoid hosting images because I don't have much storage available.
Stay tuned!
I'm happy to announce that the first version is available since May! You can play Qwixx here: https://qwixx.jboisseur.xyz
I've been working on this project for a long time. It started when I took a few Python lessons a few years ago but I abandonned because I had no clue about how to get an UI. Going back to HTML/CSS and then starting learning JavaScript put me back on tracks.
So many things! Particularly in JavaScript where I worked with arrays, listened for events, ran a huge amount of loops, created functions, toggled CSS classes, saved data in the user's browser etc. I also learned about debugging and using the web developer tools on the browser. I had to use some PHP as well, for saving best scores.
This said, I think the biggest take away was to divide the work into achievable challenges and push the harder ones at the end. Keeping this goal in mind: at the end of each step, the full game should be playable. This way, the path was most of the time enjoyable, and having something to share along the way is very rewarding.
I already started working on version 2, which is about allowing two persons to play on a same device. I'm experimenting working on cold and old code. It's very time-consuming but I try to refrain from starting all over on a blank project. I try to improve what's already there and implement what's missing to achieve this 2-players goal. One small step at a time.
The less the better BUT just in case, these CSS properties could be handy for some cosmetic touches (examples available on an ugly CodePen):
Use box-shadow and / or text-shadow property. Values: offsetX offsetY (blurRadius) (spreadRadius) color.
For instance
<p class="shadow">Lorem ipsum</p>
.shadow {
box-shadow: 2px 5px 2px 5px rgba(100, 100, 100, .25);
text-shadow: 2px 5px 2px green;
}
Use text-align-last property (right or center)
Use vertical-align property (text-top / super ; text-bottom / sub)
text-decoration shorthand property for: text-decoration-line, text-decoration-color, text-decoration-style, text-decoration-thickness
For instance :
text-decoration: underline overline dotted red 5px;
font-variant property to display text in a small-caps font for instance
Good to now: 1em corresponds to the current font size (browser default is 16px.
The solution that works in all browsers:
body { font-size: 100%; }
h1 { font-size: 2.5em; }
h2 { font-size: 1.875em; }
p { font-size: 0.875em; }
/* unvisited link */
a:link { color: red; }
/* visited link */ a:visited { color: green; }
/* mouse over link */
a:hover { color: hotpink; }
/* selected link */
a:active { color: blue; }
!important:
Also use :hover pseuo-class with a background-color property on <tr>!
Zebra-strip table with tr:nth-child(even) { background-color: #f2f2f2; }
That's all... for now.
overflow: hidden;
resize: none;
Aren't you? I'm always struggling to know where to use the for... of
loop or the for... in
loop.
Let's have here a quick note for reference:
Iterates over an iterable object (object, array, string, map...) and temporarily assign to a variable
const chars = ["Jack", "Daniel", "Sam", "Teal'c"];
for (const char of chars) {
console.log(char); }
Note that you can use const
if the variable is not reassigned within the loop.
Loops for properties of an array or object. Not to be used if the order is important.
// array
const chars = ["Jack", "Daniel", "Sam", "Teal'c"];
for (let char in chars) {
console.log(char); // prints the indexes as strings
console.log(chars[char]); // prints the value }
// object
const soldier = {firstname: "Jack", lastname: "O'Neill", team: "SG1"};
for (let key in soldier) {
console.log(key); // prints the key (firstname, lastname, team)
console.log(soldier[key]); // prints the value (Jack, O'Neill, SG1) }
The same result can be obtained using forEach() method (on an array).
const chars = ["Jack", "Daniel", "Sam", "Teal'c"];
chars.forEach(function (char, index) {
console.log(index); // prints the indexes as numbers
console.log(char); // prints the names
});
Two steps are required when it comes to building grid designs:
Imagine we work with following code:
<div id="container">
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
</div>
The corresponding CodePen is of course available.
First, we need our container to display its content as a grid : #container { display: grid; }
. After that we need to slice down the container. There's two ways to do that:
#container {
display: grid;
grid-gap: 1em;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
Here we'll have a grid of 2 columns and 2 rows.
#container {
display: grid;
grid-gap: 1em;
grid-template-areas:
"div1 div2"
"div3 div4"
}
Same here but we use names. In both cases we set up a gap, which is the space between the child element of the container.
#div1 {
grid-column: 1;
grid-row: 1;
}
div1 will go in first column and first row.
#div1 {
grid-area: div1;
}
Here we declare the element's name. As div1 was the first name on the first line, #div1 element will go on first column and first row.
For the slicing part, we can use different units, exclusively or in a combination, such as:
We can also use functions, exclusively or in combination, such as:
For the filling part, we can set up precise coordinates which will be a line or a column line number with the syntax from / to
For instance, if our first div was supposed to fill the entire first line, we could write:
#div1 {
grid-column: 1 / 3;
grid-row: 1;
}
Where we are telling the brower to extend #div1 on column 1 and 2 (column 1 is between number 1 and 2 and column 2 between number 2 and 3).
Target the right element is a must-know. Here's a recap of the available options. Examples are for the following structure:
<h2>Some title</h2>
<p>A paragraph</p>
<div>
<p>I am child of div</p>
<p>The guy up there is my bro.</p>
<section>
<p>Lonely paragraph</p>
</section>
<p>Third brother.</p>
</div>
<p>Out of div</p>
<p>Same</p>
As always, a demo is available on CodePen.
Separate the elements with a ,.
h2, section {
font-weight: bolder;
color: navy;
}
Separate the parent element from the descendant element with a space.
div p {
text-decoration: underline;
}
Separate the parent element from the child element with a >.
body > p {
font-family: monospace;
}
Separate the first bro element from the second with a +.
div + p {
text-align: center;
}
Separate the first bro element from the other ones ~.
div ~ p {
width: 20%;
padding: 0.5em;
border: 0.25em solid indianred;
}
A full list can be found on MDN Web Docs.
Use a pseudo class after the element's name you want to target:
p:first-child {
letter-spacing: 0.25em;
}
p:nth-of-type(3n) {
color: blue;
}
Locate a starting point then create inline elements or specific decoration. For instance:
h2::before {
content: "♥ ";
}
h2::selection {
background-color: gold;
}
There's no attribute in the demo page. See attribute selectors
I may have been stuck in xml model or several years ago but in the Uni course I learned that a HTML5 document doesn't validate if you close self-closing elements. You should write <img src="" alt="">,
<br>,
<hr>
etc. and not <br/>
and so on.
Here's the W3C HTML5 validator: https://validator.w3.org/nu/#textarea. You can also add an extension to your code editor.
Also, the closing tag may be omitted if a block element follows, for instance:
<p>Some text added
<ul>
<li>item 1</li>
<li>item 2</li>
</ul>
is valid.
Confusing, eh!