В ctx.fillRect координаты надобно округлять до целого, иначе квадрат может быть с размытыми краями
https://jsfiddle.net/0es19u68/ - в верхнем ряду при нечетных размерах дробные координаты, размытые края. В нижнем всё нормально.
Подробнее здесь:
https://webref.ru/layout/diveintohtml5/canvas
"Почему мы начинаем x и y c 0.5, а не с 0?"