15

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

2 Answers 2

8

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?

2
  • 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] Mar 27, 2013 at 14:01
  • @UlrikeFischer: yes, sorry, I forgot to add also the specifications within the new styles. Glad to be of help :) Mar 27, 2013 at 15:59
7

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

4
  • 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. Mar 27, 2013 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. Mar 27, 2013 at 13:48
  • Or... use a postaction with a white line of the desired thickness followed by the other postaction fadings. Mar 27, 2013 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). Mar 28, 2013 at 7:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .