HTML, CSS, and Forms
You can read this note directly if you know that a browser displays web pages. HTML gives a page its structure, CSS controls its presentation, and forms collect user input.
Beginner Mental Model
HTML and CSS run on the client side in the browser. They do not directly execute Python or change a database.
A form creates a request that a server route can process:
user enters a value
-> browser submits the form
-> Flask reads the submitted key-value pair
-> Python processes the value
-> server returns a responseFor example:
HTML input name="title" -> Flask request.form["title"]The input name and the Flask dictionary key must match exactly.
Basic HTML Document
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Book Search</title>
</head>
<body>
<h1>Book Search</h1>
<p>Find a book by title.</p>
</body>
</html>| Part | Purpose |
|---|---|
<!doctype html> | tells the browser to use modern HTML |
<html> | root element containing the document |
<head> | metadata and linked resources |
<meta charset="utf-8"> | allows Unicode text to be interpreted correctly |
<title> | text shown on the browser tab |
<body> | visible page content |
HTML elements form a nested tree. Correct nesting helps the browser interpret the page predictably.
Common Elements
| Element | Purpose |
|---|---|
<h1> | main heading |
<p> | paragraph |
<a> | hyperlink |
<img> | image |
<ul> / <ol> | unordered / ordered list |
<table> | tabular data |
<form> | user-input form |
<input> | input control |
<label> | description associated with an input |
<button> | clickable button |
Example table:
<table>
<tr>
<th>Title</th>
<th>Status</th>
</tr>
<tr>
<td>Project Report</td>
<td>Submitted</td>
</tr>
</table>Forms and Input Names
A form sends user input to the URL in its action attribute using the chosen HTTP method.
<form method="post" action="/search">
<label for="title">Title</label>
<input id="title" type="text" name="title">
<button type="submit">Search</button>
</form>Important attributes:
| Attribute | Meaning |
|---|---|
method | HTTP method, commonly get or post |
action | route that receives the submitted request |
name | key used by Flask to read the submitted value |
id | unique identifier, often connected to a label or CSS rule |
type | input type such as text, radio, checkbox, or file |
value | submitted value or initial value, depending on input type |
placeholder | short hint shown inside an empty field |
The for value of a label should match the input’s id:
<label for="email">Email</label>
<input id="email" name="email" type="text">This improves clarity and makes the label clickable.
Common Input Controls
<input type="text" name="username">
<input type="radio" id="yes" name="choice" value="yes">
<label for="yes">Yes</label>
<input type="checkbox" id="news" name="news" value="subscribe">
<label for="news">Subscribe</label>
<select name="level">
<option value="h1">H1</option>
<option value="h2">H2</option>
</select>Radio buttons that belong to one choice group share the same name. Checkboxes may submit zero, one, or several values.
GET and POST
| Method | Appropriate beginner use | Where submitted values appear |
|---|---|---|
| GET | retrieve or search for data | usually in the URL query string |
| POST | submit data for processing, uploads, or state-changing actions | request body |
A POST request does not automatically make data secure. HTTPS is still required to protect data in transit, and the server must validate and handle the data safely.
Use POST for file uploads and database inserts.
File Input
<form method="post" enctype="multipart/form-data">
<label for="photo">Choose an image</label>
<input id="photo" type="file" name="photo">
<button type="submit">Upload</button>
</form>enctype="multipart/form-data" is required because uploaded files are not sent as ordinary text fields. Flask reads them from request.files, not request.form.
CSS
CSS controls presentation, not server-side processing.
body {
font-family: Arial, sans-serif;
}
.error {
font-weight: bold;
}
#main-title {
text-align: center;
}| Selector | Meaning |
|---|---|
body | selects elements by tag name |
.error | selects elements with class="error" |
#main-title | selects the element with id="main-title" |
A class may be reused on several elements. An id should be unique within one page.
Linking an External Stylesheet
For a plain HTML page:
<link rel="stylesheet" href="style.css">In a Flask template:
<link rel="stylesheet"
href="{{ url_for('static', filename='style.css') }}">The stylesheet normally belongs in Flask’s static/ folder.
Complete Client-to-Server Trace
HTML:
<form method="post" action="/greet">
<input type="text" name="student_name">
<button type="submit">Greet</button>
</form>Flask:
@app.route("/greet", methods=["POST"])
def greet():
student_name = request.form["student_name"]
return render_template("greet.html", name=student_name)Jinja template:
<p>Hello, {{ name }}</p>The names have different roles:
| Name | Role |
|---|---|
student_name in HTML | submitted form key |
student_name in Python | local Python variable |
name passed to template | Jinja variable name |
Common Mistakes
- Giving an input no
name, so Flask cannot retrieve its value. - Using a form key in Flask that does not match the HTML input
name. - Using POST in Flask but leaving the form method as GET, or vice versa.
- Forgetting
enctype="multipart/form-data"for file uploads. - Reading an uploaded file from
request.forminstead ofrequest.files. - Confusing a CSS class selector (
.) with an ID selector (#). - Expecting CSS to validate, store, or process submitted data.
- Forgetting to link the external stylesheet.
Check Your Understanding
- What is stored inside the
<body>element? - Why does an input need a
name? - What is the difference between
idandname? - Why is
multipart/form-dataneeded for file uploads? - Does POST by itself make a submission secure?
Answers:
- The visible content and controls of the page.
- The server uses it as the key for the submitted value.
ididentifies an element in the page;nameidentifies submitted form data.- It allows files and ordinary fields to be encoded as separate parts of the request.
- No. HTTPS and safe server-side handling are still required.