Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I would like to shade a node and the border of the node.

The following code works but I don't like it very much that I have to draw something after the node on the background layer. I would prefer a solution which can be used in a style and used on the node directly. Has someone a good idea?

\documentclass{scrartcl}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\usepackage{tikz}
\usetikzlibrary{backgrounds}
\usetikzlibrary{calc}

\tikzset{
 shrink inner sep/.code={
   \pgfkeysgetvalue{/pgf/inner xsep}{\currentinnerxsep}
   \pgfkeysgetvalue{/pgf/inner ysep}{\currentinnerysep}
   \pgfkeyssetvalue{/pgf/inner xsep}{\currentinnerxsep - 0.5\pgflinewidth}
   \pgfkeyssetvalue{/pgf/inner ysep}{\currentinnerysep - 0.5\pgflinewidth}
   }}
\begin{document}
\begin{tikzpicture}
\draw (0,0) node[rectangle,
      rounded corners,
      shading=axis,
      thick,
      outer sep=0pt,
      shrink inner sep,
      left color=red!50!white,
      right color=green!50!white
       ](A){abcabc abc};
 \begin{scope}[on background layer]
 \shade[rectangle,
        left color = red,
        right color= green,
        thick,
        rounded corners=4pt+\pgflinewidth]
       ($(A.south west)+(-\pgflinewidth,-\pgflinewidth)$) rectangle
       ($(A.north east)+(\pgflinewidth,\pgflinewidth)$)
        ;
\end{scope};
\end{tikzpicture}

\begin{tikzpicture}
\draw (0,0) node[rectangle,
       rounded corners,
       fill=red!50!white,
       draw=red,
       thick
       ](A){abcabc abc};
\end{tikzpicture}      

\begin{tikzpicture}
\draw (0,0) node[rectangle,
       rounded corners,
       shading=axis,
       left color=red!50!white,
       right color=green!50!white,
       draw=red,
       thick
       ](A){abcabc abc};
\end{tikzpicture}       
\end{document}

enter image description here

share|improve this question
add comment

2 Answers 2

up vote 8 down vote accepted

This may be a possible approach; two styles have been defined:

  • horizontal shaded border which receives as arguments the left and right color: horizontal shaded border=red and green
  • vertical shaded border which receives as arguments the top and bottom color: vertical shaded border=blue and orange

The code:

\documentclass[tikz,border=10pt,png]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\tikzset{
 shrink inner sep/.code={
   \pgfkeysgetvalue{/pgf/inner xsep}{\currentinnerxsep}
   \pgfkeysgetvalue{/pgf/inner ysep}{\currentinnerysep}
   \pgfkeyssetvalue{/pgf/inner xsep}{\currentinnerxsep - 0.5\pgflinewidth}
   \pgfkeyssetvalue{/pgf/inner ysep}{\currentinnerysep - 0.5\pgflinewidth}
   }
}

\tikzset{horizontal shaded border/.style args={#1 and #2}{
    append after command={
       \pgfextra{%                 
          \begin{pgfinterruptpath}
                \path[rounded corners,left color=#1,right color=#2]
                ($(\tikzlastnode.south west)+(-\pgflinewidth,-\pgflinewidth)$) 
                rectangle
                ($(\tikzlastnode.north east)+(\pgflinewidth,\pgflinewidth)$);        
           \end{pgfinterruptpath}
        } 
    }
  },
  vertical shaded border/.style args={#1 and #2}{
    append after command={
       \pgfextra{%                 
          \begin{pgfinterruptpath}
                \path[rounded corners,top color=#1,bottom color=#2]
                ($(\tikzlastnode.south west)+(-\pgflinewidth,-\pgflinewidth)$) 
                rectangle
                ($(\tikzlastnode.north east)+(\pgflinewidth,\pgflinewidth)$);        
           \end{pgfinterruptpath}
        } 
    }
  }
}
\begin{tikzpicture}
\draw (0,0) node[rectangle,
      rounded corners,
      thick,
      outer sep=0pt,
      shrink inner sep,
      left color=red!50!white,
      right color=green!50!white,
      horizontal shaded border=red and green
      ](A){abcabc abc};
\draw (2.5,0) node[rectangle,
      rounded corners,
      thick,
      outer sep=0pt,
      shrink inner sep,
      top color=cyan!50,
      bottom color=orange!50,
      vertical shaded border=blue and orange
      ](A){abcabc abc};
\end{tikzpicture}
\end{document}

The result:

enter image description here

Notes on the code

The border is drawn after the node by means of append after command; to access the node's anchors, the macro \tikzlastnode is of help: things are very similar to How to modify nodes in TikZ to automatically add a line on their top?

share|improve this answer
    
That works nearly perfect. I had to add "thick" to the path to get the wanted line width and also had to adjust the rounded corners (like in my example) to get the same visual result as in normal nodes. So I'm now using \path[thick,rounded corners=4pt+\pgflinewidth,left color=#1,right color=#2] –  Ulrike Fischer Mar 27 '13 at 14:01
    
@UlrikeFischer: yes, sorry, I forgot to add also the specifications within the new styles. Glad to be of help :) –  Claudio Fiandrino Mar 27 '13 at 15:59
add comment

I don't know if this counts as a "good" idea. It has one big flaw, (I am on Ubuntu) I cannot view it properly in evince (the fading does not show) but can view it in okular. I cannot do anything with the resulting PDF in gimp as the fading is not preserved/respected. I had to take a screen-shot of okular to get the image for this. Which was a real nuisance.

So, not a portable solution then. I suspect it is the underlying library that deal with processing/rendering PDFs that cause the problem on Linux (presumably libpoppler). Thus, it is unlikely to be a problem on Windows.

Other than that, the idea is to use fadings which can be applied with a preaction style.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{fadings}

\tikzset{
    shade border west to east/.style args={#1 to #2}{
        preaction={draw, very thick, path fading=east, #1},
        preaction={draw, very thick, path fading=west, #2}
    },
    shade fill west to east/.style args={#1 to #2}{
        left color=#1,
        right color=#2
    }
}
\begin{document}

\begin{tikzpicture}
\node [rounded corners=1ex, 
    shade fill west to east=red!50 to green!50,
    shade border west to east=red to green] {abcabc abc};
\end{tikzpicture}

\end{document}

enter image description here

share|improve this answer
    
That's a neat idea and the result is nearly perfect on my system. The line is not thick enough (compared to a normal drawn node) but I could correct it by using postaction and thick. Claudio's code is a bit better suited for my special needs as I needed anyway something to add more things to the path and as I don't know if fadings works for the addressee of the pdf. –  Ulrike Fischer Mar 27 '13 at 13:42
    
Hmm, hadn't thought about the line width. The problem with the postaction is that the fill will show through under the inner half of the line. So, the preaction has to be used with double the required line width. –  Mark Wibrow Mar 27 '13 at 13:48
    
Or... use a postaction with a white line of the desired thickness followed by the other postaction fadings. –  Mark Wibrow Mar 27 '13 at 17:59
    
Actually I don't think that in my case (where the fill use similar colors than the border) it is a problem if the fill shows through. It looks ok. I prefer postaction as with preaction it is difficult to get identical sizes (not only of the line but only of the inner part). –  Ulrike Fischer Mar 28 '13 at 7:12
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.