Ήταν πριν από 7 χρόνια που έγραψα για το border-image για πρώτη φορά (υπάρχει ένα σχεδόν πλήρες snapshot εκείνου του άρθρου στο Internet Archive, στα Ελληνικά), για να «στυλάρω» ένα button χωρίς background-image η την τεχνική sliding doors. Εκείνη την εποχή, η υποστήριξη για border-image δεν ήταν πολύ καλή, και ταυτόχρονα οι διάφορες versions του Microsoft Internet Explorer είχαν σχετικά μεγάλο μερίδιο της «αγοράς» και δεν υποστήριζαν border-image καθόλου. Ήταν μπελάς, έπρεπε να χρησιμοποιηθεί JavaScript για να βγει το ίδιο «εφέ» σε διαφορετικούς browser ενώ το fallback ήταν τουλάχιστον άσχημο. Όμως, αυτές τις μέρες οι περισσότεροι browsers υποστηρίζουν border-image ενώ έχουμε στη διάθεσή μας και το @supports feature query, για την περίπτωση που πρέπει να υποστηρίξουμε legacy user agents.


Ας αρχίσουμε με μία κομμένη και μικρότερη σε διαστάσεις εικόνα, που μετέτραψα σε SVG βιαστικά και εν συνεχεία βελτιστοποίησα για να γλυτώσω bytes. Σύμφωνα με τα specs, το border-image property είναι shorthand για τα border-image-source, border-image-slice, border-image-width, border-image-outset και border-image-repeat, με αυτή την σειρά. Μόνο το border-image-source είναι απαραίτητο, αλλά η προεπιλογή του border-image-slice είναι 100% (της εικόνας) οπότε το τελικό εφέ πιθανότατα δεν θα αυτό που περιμένετε. Η ιδέα είναι το «κόψιμο» της εικόνας σε εννέα περιοχές — τέσσερις γωνίες, τέσσερις άκρες και το κέντρο το οποίο προς το παρόν θα αγνοήσω. Οι γωνίες μεταχειρίζονται διαφορετικά από τις άκρες, και αυτή είναι η ιδιαιτερότητα του border-image γενικώς! Βρήκα την επεξηγηματική εικόνα αυτού του κοψίματος στο MDN κάπως παραπλανητική, με το “left” λεκτικό τοποθετημένω πάνω από την πρώτη (γωνιακή) περιοχή και το “bottom” τοποθετημένο στην τέταρτη γωνιακή περιοχή, οπότε καλό είναι να θυμάστε πως η σειρά των πιθανών τιμών του border-image-slice είναι top, right, bottom, left, όπως άλλωστε συμβαίνει με τα margins, paddings, borders και άλλα CSS properties.

Το SVG για το border-image-source προέκυψε από το PNG και μετά του άλλαξα διαστάσεις σε ένα τυχαίο 180 pixels πλάτος και ύψος, μόνο και μόνο για να είναι μικρότερο από τα κουτιά με τα παραδείγματα που ακολουθούν· άδεια <span>s με 440 px max-width και 200 px ύψος:

border-style: solid;
border-width: 50px;
border-image: url("border-image-css-and-svg.svg");

Box content

Τα specs ορίζουν πως τα border-style και border-width πρέπει να έχουν τιμές για να «δουλέψει» το border-image-source. Αν δεν δώσουμε συγκεκριμένες τιμές στο border-image-slice, η εικόνα θα φανεί σε όλες τις γωνίες σύμφωνα με το μέγεθος του border-width — ούτε ιδιαίτερα χρήσιμο ούτε όμορφο! Κατά πάσα πιθανότητα δεν θα αφήνετε το border-image με όλα τα defaults, οπότε ας προχωρήσουμε.


border-style: solid;
border-width: 50px;
border-image-source: url("border-image-css-and-svg.svg");
border-image-slice: 50;

Box content

Κάτι κάνουμε τώρα! Χρησιμοποίησα ένα “μαγικό” αριθμό, 50 pixels για border-width και border-image-slice. Με αυτό τον τρόπο, το border είναι πιο παχύ απ’ όσο χρειάζεται. 37 pixels είναι μάλλον καταλληλότερο για αυτή την εικόνα· το κόψιμο θα γίνει πάνω στα «μπιλάκια» κοντά στις γωνίες. Υπενθυμίζω πως το SVG προέκυψε με πρόχειρο trace από το PNG και ίσως να μην είναι «καθαρό»:


border-style: solid;
border-width: 37px;
border-image-source: url("border-image-css-and-svg.svg");
border-image-slice: 37;

Box content

Το αποτέλεσμα είναι σχεδόν ίδιο με πριν αλλά το περιεχόμενο είναι μεγαλύτερο. Το μισό κάθε μπίλιας τεντώνεται οριζόντια (και κάθετα, αλλά το ύψος δεν είναι αρκετά μεγάλο για να φανεί) αφού το slicing κόβει τις μπίλιες στην μέση. Για να δούμε όμως και το PNG (border-image-css-and-svg.png):


border-style: solid;
border-width: 37px;
border-image-source: url("border-image-css-and-svg.png");
border-image-slice: 37;

Box content

Δεν είναι πολύ άσχημο, αλλά το SVG απλώνει καλύτερα στις πάνω και κάτω άκρες, όπως ήταν αναμενώμενο. Θα συνεχίσω με το SVG και θα δοκιμάσω κάποια ακόμα properties, όπως το border-image-width:


border-style: solid;
border-width: 37px;
border-image-source: url("border-image-css-and-svg.svg");
border-image-slice: 37;
border-image-width: 1.5;

Box content

Το αποτέλεσμα του border-image-width δεν είναι εύκολα κατανοητό, αφού βασίζεται στην μονάδα μέτρησης των τιμών. Μία τιμή χωρίς μονάδα μέτρησης (unitless) θα τεντώσει/σμικρύνει την εικόνα σε σχέση με το border-width ενώ μία τιμή επί της εκατό θα κάνει το ίδιο σε σχέση με το πλάτος ή το ύψος της εκάστοτε περιοχής!. Για να δούμε ένα ποσοστό:


border-style: solid;
border-width: 37px;
border-image-source: url("border-image-css-and-svg.svg");
border-image-slice: 37;
border-image-width: 150%;

Box content

Το αποτέλεσμα είναι αρκετά ενδιαφέρον αλλά χάθηκαν οι άκρες! Παρατηρήστε πως το border-image «ρεντάρεται» κάτω από το background του περιεχομένου. Για να δούμε τι θα γίνει αν μικρύνουμε τις τιμές των border-width και border-image-slice:


border-style: solid;
border-width: 24px;
border-image-source: url("border-image-css-and-svg.svg");
border-image-slice: 24;
border-image-width: 150%;

Box content

Εντάξει, εδώ χάνεται λίγο η μπάλα! Αφαίρεσα και το background του content ώστε να φανεί όλο το αποτέλεσμα, το οποίο είναι μάλλον… απρόβλεπτο, και ίσως γι’ αυτό το border-image να μην χρησιμοποιείται πολύ συχνά, οπότε καλύτερα να παραμείνουμε σε «λογικές» τιμές στο εξής! Να δούμε τώρα τι κάνει το border-image-outset;


border-style: solid;
border-width: 37px;
border-image-source: url("border-image-css-and-svg.svg");
border-image-slice: 37;
border-image-outset: 18px;

Box content

Το border-image-outset δέχεται ένα θετικό αριθμό και καθορίζει την απόσταση της εξωτερικής άκρης του border-image από την εξωτερική άκρη του border. Οι διαστάσεις του κουτιού δεν αλλάζουν, και το border-image δεν προκαλεί overflow ή/και scrollbars — όπως άλλωστε και το box-shadow. Για αυτό τον λόγο «χύνεται» πάνω σε οτιδήποτε υπάρχει γύρω από το κουτί. Και τέλος, τι κάνει το border-image-repeat;


border-style: solid;
border-width: 37px;
border-image-source: url("border-image-css-and-svg.svg");
border-image-slice: 37;
border-image-repeat: round stretch;

Box content

Το border-image-repeat είναι η «μαγεία» που δύσκολα επιτυγχάνεται με άλλα CSS properties. Δυστυχώς, δέχεται μόνο μία ή δύο τιμές. Αν δώσουμε μόνο ένα keyword από τα stretch, repeat, round, space (η προεπιλεγμένη τιμή είναι stretch) τότε αυτό θα αφορά σε όλες τις άκρες, αλλιώς το πρώτο keyword ρυθμίζει τις πάνω και κάτω περιοχές, ενώ το δεύτερο ρυθμίζει την εμφάνιση των δεξιά και αριστερά. Στο συγκεκριμένο παράδειγμα, ο browser χρησιμοποιεί πολλές φορές τα πάνω και κάτω κομμάτια της εικόνας ενώ τεντώνει ή σμικρύνει το πλάτος ώστε να γεμίσουν οι περιοχές και να κουμπώσουν τα γραφικά στις γωνίες. Για τις άκρες δεξιά και αριστερά το αντίστοιχο κομμάτι της εικόνας τεντώνεται για να πιάσει όλο το ύψος.


Το ίδιο περίπου αποτέλεσμα μπορεί να επιτευχθεί με background-image και background-size: 100% 100%, αλλά το εφέ επανάληψης-και-προσαρμογής-μεγέθους στις άκρες δεν μπορεί να γίνει κατ’ αυτόν τον τρόπο. Μπορούν ωστόσο να χρησιμοποιηθούν πολλάπλα background-images αλλά δύσκολα θα ταιριάξουν τα γραφικά στη σύνδεση αν τα κουτιά είναι ελαστικά! Παραδέχομαι πως το border-image δεν είναι κάτι που θα χρησιμοποιήσετε συχνά, αλλά είναι χρήσιμο εργαλείο, καλό είναι να το έχετε υπόψιν!