Sam & Max » css http://sametmax.com Du code, du cul Sat, 07 Nov 2015 10:56:13 +0000 en-US hourly 1 http://wordpress.org/?v=4.1 Servir des fichiers statiques avec nginx 10 http://sametmax.com/servir-des-fichiers-statiques-avec-nginx/ http://sametmax.com/servir-des-fichiers-statiques-avec-nginx/#comments Thu, 23 Oct 2014 06:20:02 +0000 http://sametmax.com/?p=10490 C’est un truc dont j’ai tout le temps besoin, alors l’article servira de pense bête. Marre de chercher à chaque fois :

        # sur django, on met tout dans /static/, donc par habitude je le fais
        # pour tout
        location /static/ {

            # Le dossier doit contenir le dossier 'static'. Par exemple si votre
            # arbo est /home/sametmax/repo/static, le chemin sera
            # /home/sametmax/repo. Rassurez-vous, personne n'aura accès aux
            # autres sous dossiers de "repo".
            root  /chemin/absolu/vers/dossier/;

            # On active la compression
            gzip  on;
            gzip_http_version 1.0;
            gzip_vary on;
            gzip_comp_level 6;
            gzip_proxied any;
            gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
            gzip_buffers 16 8k;

            # Sauf pour les vieux nav
            gzip_disable ~@~\MSIE [1-6].(?!.*SV1)~@~];

            # On dit au navigateur de le mettre en cache pour 3 mois. Faites gaffe,
            # mettez un param dans les url de vos balises script/link qui change
            # à chaque version du fichier, sinon vous ne pourrez pas mettre à jour
            # vos fichiers.
            expires modified +90d;
        }
]]>
http://sametmax.com/servir-des-fichiers-statiques-avec-nginx/feed/ 10
Preprocesser ses fichiers statiques et recharger son navigateur automatiquement avec Python livereload 6 http://sametmax.com/preprocesser-ses-fichiers-statiques-et-recharger-son-navigateur-automatiquement-avec-python-livereload/ http://sametmax.com/preprocesser-ses-fichiers-statiques-et-recharger-son-navigateur-automatiquement-avec-python-livereload/#comments Sun, 10 Nov 2013 06:47:39 +0000 http://sametmax.com/?p=7698 Livereload est une extension multi-navigateur qui permet de recharger tout ou partie d’une page quand un fichier a changé sur le disque.

C’est très pratique pour développer un site Web puisque si vous modifiez un template, un fichier JavaScript, une image ou un fichier CSS, vous n’avez pas besoin de cliquer sur la fenêtre du navigateur et appuyez sur F5 pour voir le résultat. Si vous avez un double écran (et si vous faites du dev Web, vous devriez), vous ne quittez pas votre éditeur de code.

L’extension est gratuite, mais le serveur existe en plusieurs version. Il y a une version graphique pour Windows et Mac qui est payante. Si vous avez un peu de budget et pas envie de vous prendre la tête, achetez là et arrêtez la lecture de l’article, c’est beaucoup plus facile.

Sinon, suivez le guide pour la version gratos en ligne de commande.

Installation

Il existe une version Python en ligne de commande du serveur : Python livereload. Il y a aussi une version pour les rubistes.

Je vous invite donc à l’installer avec pip:

pip install livereload

Il vous faudra aussi l’extension de navigateur.

Après, depuis votre terminal, mettez vous dans le dossier que vous voulez surveiller (par exemple le dossier contenant vos fichiers CSS), et lancez le serveur :

livereload

Et activez l’extension pour la page que vous voulez recharger automatiquement. Normalement, c’est juste un clic sur un bouton.

C’est bon, votre page devrait recharger automatiquement.

Rechargement à la carte

On peut choisir ce qu’on va recharger plus précisément en créant un fichier de configuration.

Créez un fichier de code Python nommé “Guardfile”, sans l’extension “.py”. Il va ressembler à ceci :

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
from livereload.task import Task
 
# watcher les js ou les css
Task.add('chemin/relatif/vers/fichier/a/surveiller.css')
Task.add('chemin/relatif/vers/fichier/a/surveiller.js')
 
# watcher les images ou les templates
Task.add('chemin/relatif/vers/dossier/a/surveiller')

Et lancez la commande livereload en étant dans le même dossier que ce fichier. Notez que le serveur ne parse ce fichier que quand l’extension est activée et que vous avez visité la page au moins une fois.

On peut même demander d’effectuer des tâches avant le rechargement de la page. Cela peut être des tâches complètement arbitraires, mais des raccourcis existent pour les tâches les plus courantes, telle que minifier du JS ou compiler un pre-processeur CSS.

Par exemple, j’utilise cette fonctionnalité pour compiler mes fichiers LESS CSS à chaque modification.

Pour cela, il faut installer le compilateur LESS. Sous Ubuntu, ça se fait en deux coups de cuillère à pot :

sudo apt-get install npm
sudo npm install -g less

Et dans le Guardfile, il faut ajouter un code du style :

from livereload.task import Task
from livereload.compiler import lessc
 
Task.add('../apps/core/static/less/boostrap/boostrap.less',
         lessc('../apps/core/static/less/boostrap/boostrap.less',
               '../apps/core/static/css/boostrap.css'))

Il y a un a tas d’options donc checkez la doc, mais aussi le code source car la doc n’est pas exhaustive.

]]>
http://sametmax.com/preprocesser-ses-fichiers-statiques-et-recharger-son-navigateur-automatiquement-avec-python-livereload/feed/ 6
Dites non aux animations 3D 15 http://sametmax.com/dites-non-aux-animations-3d/ http://sametmax.com/dites-non-aux-animations-3d/#comments Mon, 14 Oct 2013 16:07:48 +0000 http://sametmax.com/?p=7435 Juste parce que vous pouvez ne veut pas dire que vous devez, et le fait que maintenant la plupart des navigateurs supportent des belles transitions 3D ne signifie certainement PAS que vous devriez les utiliser.

En ergonomie, une règle essentielle est de ne pas mettre ou faire de choses qui n’ont pas de valeur ajoutée pour l’utilisateur.

L’esthétique est certes, en soi, une valeur ajoutée. Mais il faut considérer deux choses :

  • Cette technique apporte-t-elle une valeur esthétique qui n’est pas remplaçable par le bénéfice d’une autre technique ?
  • Le bénéfice que mon utilisateur en retire compense-t-il les inconvénients auxquels il est confronté ?

Pour les animations 3D, la réponse est clairement NON, dans 99% des cas.

D’abord, généralement l’animation est lente, ne serait-ce que pour que le mec devant son écran puisse la voir. Vu le temps qu’on passe à se faire chier à rendre une app plus rapide et fluide à utiliser, pourquoi voulez-vous, VOLONTAIREMENT et ARTIFICIELLEMENT faire patienter votre utilisateur 400ms de plus devant le slide à cube rotatif pour voir la photo suivante ?

Ensuite, malgré l’énorme progrès de nos navigateurs, ça bouffe beaucoup de ressources. Bien sûr, quand vous testez sur votre machine quad core avec chrome et un tab ouvert, c’est parfaitement fluide. Mais il suffit de jouer sur seul de ces paramètres pour que ça ne le soit plus :

  • 20 tabs sont ouverts.
  • Un autre tab utilise Javascript comme un goret (Hello Twitter !).
  • Un autre tab utilise de la 3D.
  • Un autre tab charge beaucoup d’images.
  • Un autre tab utilise flash.
  • L’utilisateur a des logiciels récents sur une vieille machine.
  • L’utilisateur utilise d’autres logiciels que son navigateur qui sollicitent la carte graphique (quelle honte, il ose avoir une vie en dehors de facebook et votre site de merde!).

Dans la vraie vie vivante, ce sont plusieurs de ces paramètres qui rentrent en compte, presque systématiquement. Et je ne vais même pas vous parler de ceux qui utilisent IE avec plein de toolbar sur une machine infectée jusqu’à la moelle. Qui sont, je le rappelle, la majorité des personnes dans le monde. Pas forcément la majorité de votre cible, mais tout de même…

…vous êtes une putain de page Web, vous ne pouvez pas pré-supposer de ce que l’utilisateur fait et dans quel contexte.

Bref, à moins d’avoir une app avec une connotation visuelle primordiale, par exemple un jeu vidéo, arrêtez avec ces foutues transitions 3D, ça rend votre app inutilisable. Les transitions 2D suffisent largement à améliorer l’ergonomie et l’esthétisme d’une page, et elles bouffent beaucoup moins.

Merci

]]>
http://sametmax.com/dites-non-aux-animations-3d/feed/ 15
De l’inutilité de <dl> 16 http://sametmax.com/de-linutilite-de/ http://sametmax.com/de-linutilite-de/#comments Sat, 30 Mar 2013 18:28:01 +0000 http://sametmax.com/?p=3261 Sémantiquement c’est génial :

<dl>
<dt>Couleurs disponibles :</dt>
<dd>Bleue</dd>
<dd>Rouge</dd>
<dt>Pas de RAM</dt>
<dt>Pays : </dt>
<dd>France</dd>
<dd>Espagne</dd>
<dd>Wonderland</dd>
</dl>

On peut faire une liste avec des sortes de titres, et on sait que les éléments de la liste sont liés par leur titre.

Sauf que :

  • Les moteurs de recherche en ont rien à foutre. On a constaté aucune différence en passant de ça à un <ul> ou même une imbrication de <div>.
  • C’est impossible à styler : on ne peut pas grouper en CSS un <dt> et ses <dd>. Et les foutre dans des conteneurs rend le code invalide.
  • On ne peut pas mettre de balise block dans le <dt>. WTF ? C’est une putain de balise de titre !

Bref, la definition list est la balise la plus inutile de tous les temps. J’ai essayé de l’utiliser dans un millions de cas de figure, au final un <ul> avec un <strong> et un <span> dans le <li> ou des <div> pour les gros morceaux sont toujours plus facile à style. Les développeurs front end peuvent se mettre la sémantique au cul.

]]>
http://sametmax.com/de-linutilite-de/feed/ 16
Les goodies CSS qu’on peut utiliser maintenant que IE6 est mort 21 http://sametmax.com/les-selecteurs-css-quon-peut-utiliser-maintenant-que-ie6-est-mort/ http://sametmax.com/les-selecteurs-css-quon-peut-utiliser-maintenant-que-ie6-est-mort/#comments Sat, 02 Mar 2013 06:35:24 +0000 http://sametmax.com/?p=3486 Avouez-le, il y a encore des trucs que vous n’osez pas utiliser, par habitude. Parce que vous avez appris pendant 10 ans que ça passait pas, et maintenant, vous êtes pas certains, alors vous continuez. Malgré le fait que la citation célèbre de Tristan Nitot soit devenu une réalité depuis des années (et que le 7 est presque mort né), on s’abstient parfois idiotement d’utiliser quelques goodies. Juste dans le doute.

Voici quelques opérations CSS que vous pouvez enfin utiliser sans danger. Promis. Ça fait des années maintenant qu’on peut sortir de sa carapace.

> – Selecteur des enfants immédiats

Selectionne les enfants du premier niveau, mais pas récursivement.

Exemple:

 
<style>
ul > li {
    margin-left:1em;
}
</style>
 
<ul>
    <li>Foo:
        <ul>
            <li>Bar</li>
            <li>Bar</li>
        </ul>
    </li>
    <li>
    Foo
    </li>
</ul>

Le sélecteur appliquera la marge aux li avec “Foo”, mais pas ceux avec “Bar”.

[attr] – Selecteur d’attribut

Sélectionne un élément s’il possède un attribut avec ce nom et cette valeur.

Exemple:

 
<style>
p[title="bouya"] {
    margin-left:1em;
}
</style>
 
<p title="bouya">Foo</p>
<p>Bar</p>
<p title="bouya">Foo</p>

Le sélecteur appliquera la marge au p avec “Foo”, mais à celui avec “Bar”.

On peut aussi faire plus raffiné en cherchant si l’attribut contient une partie de quelque chose.

:first-child – Sélecteur de premier enfant

Sélectionne un élément s’il est le tout premier enfant d’un autre.

Exemple:

 
<style>
ul li:first-child {
    margin-left:1em;
}
</style>
 
<ul>
    <li>Foo </li>
    <li>Bar</li>
</ul>

Le sélecteur appliquera la marge au li avec “Foo”, mais à celui avec “Bar”.

min/max width/height – Définir une taille minimal ou maximale

Donne une taille qu’un élément doit au moins avoir, ou peut avoir au maximum.

Exemple:

 
<style>
ul {
    min-height:3em;
    max-height:10em;
}
</style>
 
<ul>
    <li>Foo </li>
    <li>Bar</li>
</ul>

On a ici un ul de taille élastique qui va s’adapter au nombre d’éléments qu’il contient, mais il aura au moins une taille de 3em, et il ne dépassera jamais 10em.

position:fixed – Position fixée dans le viewport

Donne une position sur la partie visible de la page. Quand l’utilisateur scroll, l’élément est toujours visible à cet endroit.

Exemple:

 
<style>
ul {
    position:fixed;
    right: left;
    top: 10%;
}
</style>
 
<ul>
    <li>Foo </li>
    <li>Bar</li>
</ul>

Le menu restera toujours en haut à gauche de la page, même si je scroll. La même chose est vraie pour background-attachment: fixed que l’on peut maintenant utiliser et qui s’appliquer aux images de background.

.A.B – Sélection à classe multiple

Pour sélectionner un élément qui a les DEUX classes.

Exemple:

 
<style>
p.danger.alerte {
    color:"putainderouge";
}
</style>
 
<p class="danger">Bar</p>
<p class="alerte">Bar</p>
<p class="danger alerte">Foo</p>

Seul le p avec “Foo” sera en rouge.

blockquote + p – Sélection des éléments adjacents

Sélectionne un élément s’il est juste après un autre.

 
<style>
blockquote + p {
    font-style:italic;
}
</style>
 
<blockquote>
Rien ne sert de ramer quand on attaque la falaise.
</blockquote>
<p>Anonyme</p>
 
<p>Et maintenant quelque chose de complètement différent.</p>

Le nom de l’auteur de la citation va être mis en italique. Mais pas le second p.

Et en prime

On cite souvent:

  • :first-line – First line selector of content copy.
  • :first-letter – First letter selector of content copy.

Mais en vérité ils étaient déjà supportés par IE6.

Par contre, tous ces trucs qui marchaient, mais auxquels il fallait faire super gaffe :

  • float: right et clear:both
  • z-index
  • :hover. Pas juste sur les a. Partouuuuuuuuuuut. (marche uniquement si on précise le doctype, mais qui ne le fait pas ?)

Ça marche comme pour tous les autres maintenant.

En plus on a les PNGs transparents (24 bit).

Et d’après ce post sur SO, on s’affranchit aussi des bugs suivant :

Mais gaffe quand même pour les micros IE7 qui reste (il doit pas en rester des masses). Il compte parfois les commentaires comme des éléments sélectionnables par les sélecteurs qu’on vient de voir :-(.

Sinon, souvenez-vous que la compatibilité IE9 pour IE7 et 8 est à la portée d’un tout petit include Javascript.

]]>
http://sametmax.com/les-selecteurs-css-quon-peut-utiliser-maintenant-que-ie6-est-mort/feed/ 21
Évolution de la courbe d’apprentissage d’un dev front end 12 http://sametmax.com/evolution-de-la-courbe-dapprentissage-dun-dev-front-end/ http://sametmax.com/evolution-de-la-courbe-dapprentissage-dun-dev-front-end/#comments Mon, 07 Jan 2013 16:42:50 +0000 http://sametmax.com/?p=4029 ]]> http://sametmax.com/evolution-de-la-courbe-dapprentissage-dun-dev-front-end/feed/ 12 Firefox n’affiche plus les styles CSS ni les images 6 http://sametmax.com/firefox-naffiche-plus-les-styles-css-ni-les-images/ http://sametmax.com/firefox-naffiche-plus-les-styles-css-ni-les-images/#comments Fri, 04 Jan 2013 12:15:30 +0000 http://sametmax.com/?p=3956 Après avoir vidé le cache, il peut arriver que notre panda roux n’affiche plus les styles CSS ou les images: il n’y a plus aucune mise en page, juste du texte noir sur une page blanche. Damned !

La solution est de forcer le refresh de la page et du cache avec Ctrl + Shift + R.

]]>
http://sametmax.com/firefox-naffiche-plus-les-styles-css-ni-les-images/feed/ 6
Comment servir les fichiers statiques avec Django en dev et en prod 13 http://sametmax.com/comment-servir-les-fichiers-statiques-avec-django-en-dev-et-en-prod/ http://sametmax.com/comment-servir-les-fichiers-statiques-avec-django-en-dev-et-en-prod/#comments Mon, 22 Oct 2012 22:57:28 +0000 http://sametmax.com/?p=2706 Servir les fichiers CSS, javascript et les images avec Django a toujours été la plus grande source de confusion (heureusement ça s’est bien amélioré avec la 1.4, donc upgradez si vous pouvez). C’est d’autant plus déroutant que la manière de faire est différente selon la version de Django, et selon que l’on est en production ou en développement.

Donc, pour profiter de cet article:

  • Lisez les parties qui vous concernent uniquement.
  • Ne lisez pas en diagonale.
  • Si ça ne marche pas, partez de zéro (avec un projet tout neuf), et une fois que ça marche, essayez sur le votre.

C’est typiquement le cas où il faut comprendre ce qui se passe et pas juste copier/coller du code (ceci est une petite pique à Max qui est en train de décuver comme une loque sur le canap pendant que j’écris cette partie de l’article).

Préparation

Les fichiers statiques se gèrent à base de chemins absolus. Afin de faciliter celà, vous devriez donc toujours avoir ceci tout en haut de votre fichier settings.py:

import os
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))

Si votre fichier de settings n’est pas à la racine du projet (typiquement dans un projet Django 1.4), faites:

import os
SETTINGS_DIR = os.path.dirname(os.path.abspath(__file__))
PROJECT_DIR = os.path.dirname(SETTINGS_DIR)

Le fichiers de settings étant un fichier Python, on peut mettre tout le code que l’on souhaite dedans, et ce code nous permet d’obtenir de manière dynamique le chemin absolu vers votre dossier de projet. Il servira de base pour tous les chemins vers les fichiers statiques.

__file__ contient le chemin vers le fichier en cours. abspath() permet d’obtenir le chemin absolu. dirname() permet d’obtenir le nom du dossier contenant le fichier.

Notez aussi l’emplacement des fichiers statiques de la Django admin dans un coin (dans la doc de votre site par exemple). Ces fichiers se trouvent dans django/contrib/admin/media, mais si vous galerez pour les trouver, vous pouvez toujours lancer la commande:

python -c "import django, os; print os.path.join(os.path.dirname(django.__file__), 'contrib/admin/media')"

Moi ça donne un truc comme ça:

/home/sam/.virtualenvs/project_env/local/lib/python2.7/site-packages/django/contrib/admin/media

En phase de développement, de la version 1.0 à la version 1.2

Vous êtes sur votre machine, et vous utilisez la commande runserver. C’est donc Django qui va servir vos fichier statiques, et nous allons voir comment, pour chaque version de Django, on peut lui demander de le faire.

C’est une vieille version, servir les fichiers statiques est assez relou, alors on va gruger pour vous faciliter la vie. Non, ce n’est pas la meilleur manière de faire, mais c’est la manière de faire qui vous évitera de retourner sur un forum pour demander pourquoi ça ne marche pas.

Créez un dossier nommé “static” à la racine de votre projet. Mettez tous vos fichiers statiques dedans: js, css, images… Organisez ça en sous-dossier si vous voulez, mais mettez tout dedans, y compris les fichiers statiques des autres apps Django que vous avez installé (et qu’il va falloir copier/coller ou alors faire un lien symbolique). La seule exception est l’admin.

Ce n’est pas particulièrement propre ni pratique, mais ça va marcher. Le surcoût en maintenant sera largement compensé par le fait que ce sera très simple à comprendre et à servir.

Dans votre fichier de settings, pointez MEDIA_ROOT sur ce dossier:

MEDIA_ROOT = os.path.join(PROJECT_DIR, 'static')

Et choissisez un chemin explicite pour MEDIA_URL:

MEDIA_URL = '/static/'

Ne touchez pas à ADMIN_MEDIA_PREFIX. Ne mettez pas MEDIA_URL égale à ADMIN_MEDIA_PREFIX.

Dans le fichier urls.py principal, c’est à dire ce lui est généralement à la racine de votre projet, faites:

# on importe ici tout les trucs nécessaires à urls.py
from django.conf.urls.defaults import *
# on va récupérer MEDIA_ROOT depuis le fichier de settngs
from django.conf import settings
 
# on active l'admin
from django.contrib import admin
admin.autodiscover()
 
# on créé un pattern vide. Cela va nous permettre d'insérer le service
# des fichiers statiques en premier
urlpatterns = patterns('')
 
# On active maintenant le service des fichiers statiques par Django
# mais uniquement en mode DEBUG (pour éviter de l'oublier en prod)
if settings.DEBUG:
    urlpatterns += patterns('',
        (r'%s/(?P<path>.*)$' % settings.MEDIA_URL.strip('/'),
         'django.views.static.serve',
         {'document_root': settings.MEDIA_ROOT}),
    )
 
# Ensuite on déclare nos patterns normalement
# ATTENTION, le signe doit-être "+=", pas "=", sinon vous allez tout écraser
urlpatterns += patterns('',
    # Example:
    (r'^', include('app.urls')),
 
    # Uncomment the admin/doc line below and add 'django.contrib.admindocs'
    # to INSTALLED_APPS to enable admin documentation:
    (r'^admin/doc/', include('django.contrib.admindocs.urls')),
 
    # Uncomment the next line to enable the admin:
    (r'^admin/(.*)', admin.site.root),
)

Vous notez que contrairement à ce qu’on voit la doc officielle, on met l’url pour les fichiers statiques en premier. Cela donne une forme étrange à la déclation des urls car on a un urlpatterns vide au début, mais c’est très important: à un moment vous allez déclarer une URl attrape-tout qui court-circuitera tout ce qu’il y a après, et ce jour là vous passerez des heures à chercher pourquoi vos fichiers statiques ne sont pas déclarés.

Le strip() n’est pas obligatoire si vous mettez les slashes correctement partout. Mais ce n’est jamais le cas.

Maintenant, dans votre html, vous pouvez faire ceci:

<link href="/static/chemin/du/fichier/a/relatif/au/dossier/static.css"  rel="stylesheet" />

Et pareil pour le js, les images, etc.

Le chemin est bel et bien écrit en dur dans le templates HTML. Encore une fois, ce n’est pas la meilleure manière de faire, c’est juste celle qui vous garanti que ça marche. Si vous vous sentez à l’aise avec le processus, vous pouvez changer celà en utilisant un context_processor pour ajouter MEDIA_URL à chaque template et remplacer /static/ par {{ MEDIA_URL }}.

Télécharger le projet complet d’exemple

En phase de développement, pour la version 1.3 et 1.4

C’est globalement beaucoup plus facile. Il suffit de mettre tous vos fichiers statiques dans un dossier nommé “static” dans le dossier d’une de vos app pour qu’ils soient trouvés automatiquement quand vous lancerez manage.py runserver.

Voici à quoi ressemblera votre settings.py:

# plus rien à voir avec avant, MEDIA_ROOT et MEDIA_URL designent
# l'endroit où vous voulez que vos utilisateur upload et download des fichiers
# Ce n'est donc plus un paramètre primordial
MEDIA_ROOT = os.path.join(PROJECT_DIR, 'media')
MEDIA_URL = '/media/'
 
# Ce qui s'appelait avant MEDIA_ROOT s'appelle maintenant STATIC_ROOT
# mais il n'est utile pour la prod
# On le met quand même pour plus tard
STATIC_ROOT = os.path.join(PROJECT_DIR, 'static')
 
# Le settings le plus important: à quelle adresse servir les fichiers statiques
# Utile en dev afin de pouvoir bénéficier des templates tags
STATIC_URL = '/static/'
 
# Les medias de l'admin sont enfin une URL comme une autre qu'on peut
# mettre sous notre propre arborescence
ADMIN_MEDIA_PREFIX = '/static/admin/'
 
# Vous pouvez OPTIONNELLEMENT rajouter ici une liste de chemin vers
# des dossiers de fichiers statiques qui seront ainsi aussi servit automatiquement
# pendant le développement. Par exemple un dossier à la racine
STATICFILES_DIRS = (
    os.path.join(PROJECT_DIR, 'more_static'),
)
# N'utilisez PAS le même dossier que STATIC_ROOT

Il n’y a rien à faire de plus, vos fichiers seront servis automatiquement en dev, pas besoin de toucher aux urls.

Maintenant il faut juste les déclarer vos URLs dans le template.

Pour Django 1.3, vous pouvez ajouter un fichiers statiques ainsi pour éviter d’écrire l’URL en dur:

{% load static %}
{% get_static_prefix as STATIC_PREFIX %}
 
<link href="{{ STATIC_PREFIX }}app/css/style.css"  rel="stylesheet" />

Pour django 1.4, c’est encore plus simple:

{% load staticfiles %}
<img src="{% static "app/css/style.css" %}" />

Encore un détail, si vous n’utilisez pas le serveur de dev Django mais un autre serveur de dev (ex: werkzeug), vos fichiers statiques ne seront pas servis automatiquement, mais il est facile d’y remédier. Ajoutez à votre urls.py:

from django.contrib.staticfiles.urls import staticfiles_urlpatterns
 
urlpatterns += staticfiles_urlpatterns()

Télécharger le projet complet d’exemple

Migration de 1.2 ou moins vers 1.3 ou 1.4

Bouger vos fichiers statiques du répertoire à la racine vers le répertoire nommé “static” d’une de vos apps (ou de plusieurs).

Ajoutez ceci dans votre fichier de config:

STATICFILES_DIRS = (
)
 
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)

Et ajoutez django.contrib.sites à vos INSTALLED_APPS.

Remplacez toutes les URls en dur dans le HTML par une version avec les templates tags (voir partie précédente).

Attention, ça ne couvre que la partie pour la gestion des fichiers statiques, il y a d’autres choses à migrer.

En production: toutes versions

Je ne vais pas expliquer ici comment mettre Django en production (c’est un article à lui tout seul, peut être même plusieurs). Ici je vais me concentrer sur comment servir les fichiers statiques, et présupposer DEBUG = False.

Si vous utilisez Djagno 1.2 ou moins, vous n’avez rien à faire côté Django. Si vous utilisez Django 1.3 ou 1.4, vous devez maintenant appeler la commande pyhon manage.py collectstatic. Celle-ci va prendre tous les fichiers statiques de tous les dossiers “static” des apps et ceux listés dans STATICFILES_DIRS et va les copier dans STATIC_ROOT.

Dans tous les cas, vous n’aurez qu’un seul dossier pour le js, le css et les images à servir avec Nginx ou Apache.

Nginx

Si vous avez votre propre serveur, je vous conseil Nginx plutôt qu’Apache pour mettre votre site en prod.

L’idée est de dire dans le fichier de configuration nginx que toutes les URLs qui concernent les fichiers statiques sont servies directement par Nginx, et les autres sont passées à Django:

server {
        listen      8080;
 
        ############################################################
        # la partie qui concerne les fichiers statiques commence ici
        ############################################################
 
        location /favicon.ico {
            # favicon.ico doit être à la racine du dossier img
            root  /chemin/absolu/vers/dossier/img;
        }
 
        # on sert nos fichiers statiques
        # l'url doit correspondre à MEDIA_URL
        location ~* ^/static/ {
            root  /chemin/absolu/vers/dossier/PARENT/du/dossier/statique;
            # on active gzip pour tous les petits fichiers qui contiennent du texte
            # si le navigateur le supporte
            gzip  on;
            gzip_http_version 1.0;
            gzip_vary on;
            gzip_comp_level 6;
            gzip_proxied any;
            gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
            # petite astuce gzip pour les gros fichier
            # voir http://blog.leetsoft.com/2007/7/25/nginx-gzip-ssl
            gzip_buffers 16 8k;
 
            # on desactive gzip pour les vieux navigateurs
            gzip_disable ~@~\MSIE [1-6].(?!.*SV1)~@~];
        }
 
       # on fait pareil mais pour l'admin Django
       # l'url doit corresponde à ADMIN_MEDIA_PREFIX
       location ~* ^/media/ {
            root  /chemin/absolu/du/dossier/PARENT/du/dossier/media/de/django;
            gzip  on;
            gzip_http_version 1.0;
            gzip_vary on;
            gzip_comp_level 6;
            gzip_proxied any;
            gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
            gzip_buffers 16 8k;
            gzip_disable ~@~\MSIE [1-6].(?!.*SV1)~@~];
        }
 
        ##############################################################
        # la partie qui concerne les fichiers statiques se termine ici
        ##############################################################
 
        location / {
            proxy_pass http://127.0.0.1:8000;
        }
}

Notez bien que la directive root suppose que vous mettiez le dossier parent du dossier que vous voulez servir, et que le dossier servi a le même nom que le chemin dans l’url.

Par exemple, si vos fichiers statiques sont dans /home/sam/project/static, alors l’url devra être ^/static/ et on passera à l’instruction root le chemin /sam/project.

Apache

Si vous êtes chez un hébergeur qui n’a qu’Apache, voici un manière de servir les fichiers statiques. Je ne connais pas Apache aussi bien que Nginx, donc je ne peux pas m’engager sur la gestion de Gzip.

# TOUS les chemins doivent être accessible pour le user apache (www-data le plus souvent)
# N'oubliez pas les slashes finaux, ils sont importants
 
WSGIPythonPath /chemin/absolu/vers/project/:/chemin/absolu/vers/dossier/parent/du/project/:/chemin/vers/site/package/du/virtualenv/
 
<VirtualHost *:80>
 
    WSGIScriptAlias / "/chemin/absolu/vers/fichier/project.wsgi"
 
    ########################################################
    # Début de la partie qui concerne les fichiers statiques
    ########################################################
 
    # on sert les fichiers statiques du site
    Alias /static/ "/chemin/absolu/vers/dossier/static/"
    Alias /favicon.ico "/chemin/absolu/vers/dossier/static/img/favicon.ico"
 
    # on donne l'autorisation à tous de les lire
    <Directory "/chemin/absolu/vers/dossier/static/">
        Order allow,deny
        Allow from all
    </Directory>
 
    # on sert les fichiers statiques de l'admin
    Alias /media/ "/chemin/absolu/vers/dossier/django/contrib/admin/media/"
    # on donne l'autorisation à tous de les lire
    <Directory "/chemin/absolu/vers/dossier/django/contrib/admin/media/">
        Order allow,deny
        Allow from all
    </Directory>
 
    ######################################################
    # Fin de la partie qui concerne les fichiers statiques
    ######################################################
 
</VirtualHost>

Si vous faites bien gaffe aux droits d’accès des dossiers (récursivement) et que vous avec pas oublié de “/” à la fin d’un chemin, tout ira bien.

Pour Apache, servir les fichiers statiques est généralement la partie facile, c’est faire marcher Django et mod_wsgi qui est difficile: problèmes de droits, mauvaise configuration, Python path qui foine… Mais je m’en branle, puisque c’est pas l’objet de l’article, donc démerdez-vous.

Notes de fin

Jusqu’à la version 1.2, MEDIA_ROOT et MEDIA_URL ne sont que des conventions qui ne servent pas à grand chose à part à être utilisées par des contexts managers et à vous éviter les chemins en durs dans les templates et urls.py.

A partir de Django 1.3, STATIC_ROOT et STATIC_URL sont vraiment utilisées: STATIC_ROOT est là où Django va mettre le resultat de la commande collecstatic et STATIC_URL et l’url que va utiliser la vue staticfiles_urlpatterns.

MEDIA_ROOT et MEDIA_URL existent toujours, mais sont utilisés pour designer le dossier et l’url qui pointent vers les contenus uploadés et downlodés par les utilisateurs. Si vous voulez les servir, il faut faire exactement la même chose à l’époque de Django 1.2 et avant: mettre la route à la main dans urls.py (mais cette fois, il y a un raccourcis pour ça), et rajouter une entrée supplémentaire dans le fichier de conf Nginx ou Apache.

Sinon, vous pouvez aussi vous éviter tout ce merdier en utilisant le middleware qui sert automatiquement tous les fichiers statiques de django_quicky.

Enfin, je n’ai pas abordé les storage backends, tout simplement parce que je n’en utilise pas, donc je ne peux pas vous donner de bons conseils sur la question.

]]>
http://sametmax.com/comment-servir-les-fichiers-statiques-avec-django-en-dev-et-en-prod/feed/ 13
LiveCss.js: refraichir les CSS sans recharger la page 7 http://sametmax.com/livecss-js-refraichir-les-css-sans-recharger-la-page/ http://sametmax.com/livecss-js-refraichir-les-css-sans-recharger-la-page/#comments Sat, 09 Jun 2012 01:21:43 +0000 http://sametmax.com/?p=893 LiveCss.js est une petite bibliothèque javascript qui rafraichie les styles CSS d'une page quasiment en temps réel, sans la recharger. Elle est distribuée sous licence Do what the fuck you want par the Sam et Max incorporation company of the world.]]> EDIT: vu que live.js fait la même chose en mieux, il n’y a pas de raison de continuer le développement de LiveCss.js

LiveCss.js est une petite bibliothèque javascript qui rafraichie les styles CSS d’une page quasiment en temps réel, sans la recharger. Elle est distribuée sous licence Do what the fuck you want par the Sam et Max incorporation company of the world.

Le plus simple pour l’utiliser est le format bookmarklet. Il suffit de glisser et déposer le lien suivant dans vos favoris :

Quand vous voulez activer LiveCss.js, cliquez sur le favoris. Pour le désactiver, cliquez à nouveau.

Il n’y a rien de plus à faire. Éditez votre CSS comme d’habitude, et au moment de sauvegarder, la page sera mise à jour automatiquement.

ATTENTION

Du fait de la politique de sécurité de certains navigateurs, liveCss.js pourrait ne pas fonctionner avec le protocole file:// (en local). Pour ces navigateurs, on peut contourner le problème en lançant un petit serveur Web à la racine du projet.

Python (nativement installé sur la plupart des systèmes GNU/Linux et Mac OS), vous permet de le faire en une commande:

python -m "SimpleHTTPServer"

On peut ensuite accéder aux pages à l’adresse http://127.0.0.1:8000

Usage manuel

Si vous avez besoin d’un peu plus de contrôl sur l’exécution de LiveCss.js, vous pouvez inclure la bibliothèque elle même dans la page (mais n’oubliez pas de la retirer avant le passage en prod) :

 

Ensuite juste en dessous :

<script type="text/javascript">// <![CDATA[
      liveCss.start();
 
// ]]></script>

C’est tout.

Il y a plusieurs options avec lesquelles on peut jouer :

    liveCss.start(); // recharge les fichiers CSS toutes les demies secondes
    liveCss.stop(); // arrête de recharger les fichiers CSS
    liveCss.toggle();  // commencer ou arrêter de recharger les fichiers CSS
    // toggle préserve l'état du plugin si on ne lui passe pas de paramètres
    // contrairement à start/stop/start
 
    liveCss.start({interval: 100}); // recharge les fichiers toutes les secondes
 
    // recharge les fichiers CSS dont l'adresse est
    // "./static/css/style.css" ou "./static/css/ie.css"
    liveCss.start({stylesheets: ["./static/css/style.css", "./static/css/ie.css"]});
 
    // positioner la petit boite verte qui vous dit quand LiveCss.js est
    // en train de tourner en bas à droite
    // (ce doit être au format du positionnement absolu en CSS)
    liveCss.start({hintPosition: 'right:0;bottom:0'});

Ajustez ces paramètres pour avoir un rafraichissement plus rapide. Vous pouvez bien entendu utiliser plusieurs options en même temps.

Notez bien que l’utilisation de debuggers comme Firebug en même temps que LiveCss.js pourrait être lent car ils inspectent la stack alors que LiveCss.js utilise une boucle récursive infinie. C’est utilisable, mais pas aussi rapide que l’expérience habituelle.

Comment ça marche?

La bibliothèque lance une boucle infinie avec un timer entre chaque tour, durant lesquels elle charge chaque fichier CSS en AJAX. A chaque requête, le CSS est dumpé dans un tag de style inline et le noeud de style correspondant est désactivé.

LiveCss.js s’inspire de css_autoreload, le mode watch de less.js et Xrefresh, mais est très jeune en comparaisons. Attendez-vous donc à des bugs, surtout que pour le moment ce n’est testé que sous Firefox.

Comme d’hab, merci de rapporter les bugs, ou de nous notifier si ça marche sous une autre config qu’on puisse l’ajouter à la liste des compatibilités. N’hésitez pas à postez vos success stories en commentaire du genre:

Depuis que j’utilise LiveCss.js, j’ai perdu du poids et je n’ai plus de problème d’érection

.

]]>
http://sametmax.com/livecss-js-refraichir-les-css-sans-recharger-la-page/feed/ 7