The reason for your problem is that a left join will fill in null values when there are no matching rows in a table.
Thus, when you select FROM student, those who did not attend will have null values in att, and thus will have null values in class, which means that your where clause will exclude such students in the same way as if you had done an inner join.
However, since you are supposed to show attendance for one class per page, you must allready know which class is in question. For example, to show attendance for a specific class, the user somehow selects which class to view such as clicking "Physics, class 1" or "Physics, class 2".
As such, you have an anchor looking like this (or a similar way of doing it with select boxes)
<a href="?class_id=1&att_id=1&class=Physics%2C+class+1">Physics, class 1</a>
You would simply redisplay the query string attribute for "class" directly
printf('<h2>%s</h2>', $_GET['class']);
And since you don't need to include the class title you simply
$class_id = (int) $_GET['class_id'];
$att_id = (int) $_GET['att_id'];
$query = printf
(
'SELECT fname, lname
FROM student
LEFT JOIN att ON att.student_id = student.id AND att_id=%d AND class_id=%d',
$att_id,
$clas_id
);
It's once again worth noting that you can't place class_id and att_id in a where clause, since that has nothing to do with how the join is performed and would actually exclude non-attending students, whereas the join allows rows from students which have no matching rows in att for the join to be filled with null values.